一 前言
本文出自Butter Knife官博,地址如下:
http://jakewharton.github.io/butterknife/
以下翻译的案例基于Butter Knife 8.4.0版本
二 介绍
Butter Knife通过注解字段@BindView
和view ID,在你的布局中去查找并自动生成相应的view
class ExampleActivity extends Activity {
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
生成代码时才执行查找配对相应的控件,而不是利用相对较慢的反射。调用bind
委托生成你可以查看并调试的代码。
上面的示例生成的代码大致相当于如下代码:
public void bind(ExampleActivity activity) {
activity.subtitle = (android.widget.TextView) activity.findViewById(2130968578);
activity.footer = (android.widget.TextView) activity.findViewById(2130968579);
activity.title = (android.widget.TextView) activity.findViewById(2130968577);
}
资源绑定
绑定预定义的资源是通过注解@BindBool
, @BindColor
, @BindDimen
, @BindDrawable
, @BindInt
, @BindString
结合一个R.bool.ID
(或者你指定的任一类型)来绑定他相应的字段
class ExampleActivity extends Activity {
@BindString(R.string.title) String title;
@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red; // int or ColorStateList field
@BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field
// ...
}
非activity的绑定
也可以通过自己的root view来执行任意对象的绑定。
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
}
另一种使用方式是,在list adapter的view holder中绑定。
public class MyAdapter extends BaseAdapter {
@Override public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view != null) {
holder = (ViewHolder) view.getTag();
} else {
view = inflater.inflate(R.layout.whatever, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
}
holder.name.setText("John Doe");
// etc...
return view;
}
static class ViewHolder {
@BindView(R.id.title) TextView name;
@BindView(R.id.job_title) TextView jobTitle;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}
你可以通过上面提供的示例看到具体的实现。
调用ButterKnife.bind
在你所有使用findViewById
的地方。
其他绑定APIs:
- 以activity为顶层视图绑定任意对象。如果你使用了类似MVC的模式,你可以在控制器中(controller),通过它的activity来绑定
ButterKnife.bind(this, activity)
- 在fields中绑定子视图通过
ButterKnife.bind(this)
。如果你的layout中使用了<merge>
标签和自定义view的构造函数,你可以在之后立即调用这个函数。另外,自定义view通过xml构建时,可以在onFinishInflate()
回调中使用
视图列表
你可以把多个views放入一个集合或数组中
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
apply
方法允许你在一个集合中的所有视图立即起作用
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
Action
和Setter
接口允许指定一些简单的行为。
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(value);
}
};
一个安卓属性Property
也可以使用的'apply'方法来设置。
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
绑定监听事件
Listeners 也能被自动配置到方法上
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
Listener方法的所有参数都是可选的。
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}
定义一个指定类型的参数,它会自动转换
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
可以为一个公共事件绑定多个ID
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}
自定义控件可以不通过指定ID来绑定listeners
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}
绑定重置
fragment与activity相比,view的生命周期是不同的,在onCreateView
中绑定fragment时,需要在onDestroyView
中设置views为null。当你调用bind
时,Butter Knife会返回一个Unbinder实例。在bind
所相对应的生命周期中调用unbind
方法解绑
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
private Unbinder unbinder;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
// TODO Use fields... return view;
}
@Override public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}
可选绑定
默认情况下,@Bind
和Listener的绑定都是必要的。如果找不到view对象,将会导致抛出异常。
为了防止这种情况的出现,可以添加一个@Nullable
注解或者是@Optional
注解。
注意:@Nullable
可以在任意fields使用,这是希望开发者能够通过Android's "support-annotations" library更多的使用@Nullable
注解
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
多种监听方法
方法注解所对应的监听有多个回调函数可用于绑定到他们中的任何一个。每个注解都会绑定一个默认的回调函数。使用回调参数指定另一个。
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
额外说明
ButterKnife也引入了简化过的findById
方法,方便在view,activity,dialog中查找对应的view,它使用泛型来得到返回类型,并自动进行转换。
View view = LayoutInflater.from(context).inflate(R.layout.thing, null);
TextView firstName = ButterKnife.findById(view, R.id.first_name);
TextView lastName = ButterKnife.findById(view, R.id.last_name);
ImageView photo = ButterKnife.findById(view, R.id.photo);
通过添加静态方法butterknife.findbyid
来实现,最后希望你更多的享受到编程的乐趣。
下载
gradle
compile 'com.jakewharton:butterknife:(insert latest version)'
apt 'com.jakewharton:butterknife-compiler:(insert latest version)'
License
Copyright 2013 Jake Wharton
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.