简介
正如其官网所说:"Field and method binding for Android views"
,ButterKnife是对Android view的属性和方法的强大的绑定注解框架。
GitHub地址:https://github.com/JakeWharton/butterknife/
官网地址:http://jakewharton.github.io/butterknife/
它能节省很多代码量,像findViewById
这种代码就不用再出现了,而且这个框架也提供了很多其他有用的注解,可以大大的提升开发效率!
配置
现在最新版本为butterknife:8.4.0
在Gradle中添加依赖:
compile 'com.jakewharton:butterknife:8.4.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
使用
①在Activity中使用
我们需要在声明变量的时候添加注解:
@BindView(R.id.text)
TextView textView;
@BindView(R.id.button)
Button button;
之后在setContentView()
之后调用:
ButterKnife.bind(this);
声明的控件就可以使用了!
这里需要注意的问题:
1. Activity中ButterKnife.bind(this);
必须在setContentView();
之后调用,且父类bind绑定后,子类不需要再bind,所以我们一般可以把它写在BaseActivity中!
2. 声明的属性不能用private或者static修饰,否则会报错!
②在Fragment中使用
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;
}
}
在重载的bind()方法中,传入根布局即可!
③在Adapter中使用
Adapter有一种常用的优化策略,就是使用ViewHolder来减少findViewById()的重复调用。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.person_item_layout, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Person person = getItem(position);
if (null != person) {
holder.name.setText(person.getName());
holder.age.setText(String.valueOf(person.getAge()));
holder.location.setText(person.getLocation());
holder.work.setText(person.getWork());
}
return convertView;
}
static class ViewHolder {
@BindView(R.id.person_name)
TextView name;
@BindView(R.id.person_age)
TextView age;
@BindView(R.id.person_location)
TextView location;
@BindView(R.id.person_work)
TextView work;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
ButterKnife.bind()方法可以被放在任何你想使用findViewById的地方。
提供的其他绑定API:
1. 使用Activity在任意对象中进行绑定。如果你使用了类似MVC的编程模式,你可以使用ButterKnife.bind(this, activity)
在Controller中进行绑定
2. 使用ButterKnife.bind(this)
绑定一个布局的子布局到变量上。如果你在布局中使用了<merge>
标签并且在自定义的控件构造时inflate这个布局,你可以在inflate之后立即调用它。或者,你可以在onFinishInflate()
回调中使用它。
④绑定资源
绑定资源到属性上可以使用@BindBool
、@BindColor
、@BindDimen
、@BindDrawable
、@BindInt
、@BindString
。使用时对应的注解需要传入对应的id资源,例如@BindString
你需要传入R.string.id_string
的字符串的资源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
// ...
}
⑤View List,绑定多个view
我们可以使用@BindViews
把多个view放在集合或数组中进行绑定:
@BindViews({R.id.edit1,R.id.edit2,R.id.edit3})//里边要有大括号
List<EditText> editTexts;
注意:id用逗号分隔,大括号包围,外面才是小括号.
使用这种绑定时,你可以使用apply()函数。该函数相当于将在这个列表中每一个元素上进行调用,为一组对象批量地设置值.
apply()有三种重载方法:
public static <T extends View> void apply(List<T> list, Action<? super T> action)
public static <T extends View, V> void apply(List<T> list, Setter<? super T, V> setter, V value)
public static <T extends View, V> void apply(List<T> list, Property<? super T, V> setter, V value)
其中Action
和Setter
是ButterKnife中的两个接口:
public interface Action<T extends View>{
@UiThread
void apply(@NonNull T view, int index);
}
public interface Setter<T extends View, V>{
@UiThread
void set(@NonNull T view, V value, int index);
}
在使用的时候需要我们自行实现这两个接口,然后传入对象。Setter的第三个参数是指定要set什么值!
Property
是Android中的类,它包含view的一些基本属性,比如透明度,平移,缩放,旋转等。可以这样使用:
ButterKnife.apply(editTexts, View.ALPHA, 0.0f);
⑥绑定监听事件
@OnClick(R.id.button)
void test(View view){
Toast.makeText(this,"点击事件",Toast.LENGTH_SHORT).show();
}
注意:这里方法仍然不能是private和static, 并且可以有一个参数View,也可不写.并且写的时候可以直接写一个具体的子类,比如参数View可以写成Button,这里的cast是自动完成的.
除了点击事件@OnClick
,还有ListView的点击@OnItemClick
, CheckBox的@OnCheckedChanged
等等.
另外可以一次指定多个id,为多个View绑定一个事件处理方法,比如:
@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();
}
}
最后,当我们自定义View的时候,绑定监听事件则不需要指定id:
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}
⑦绑定重置
可以用undind()
方法将ButterKnife注入的View引用设置为null.
比如在Fragment的onCreateView()
里调用ButterKnife.bind()
方法注入了一些View,这个方法会返回一个Unbinder 对象,在onDestroyView()
里想把它们置为null,可以直接调用unbinder.undind(this);
方法.
⑧可选的绑定
在默认情况下, @BindView
和监听器的绑定都是需要目标view的,如果目标view没有找到的话,Butter Knife将会抛出一个异常。
如果你并不想接收到这样的信息,那么就在你的方法或变量上使用@Nullable
或者@optional
吧。
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
⑧多方法的Listener
有一些View的listener是有多个回调方法的,比如Spinner的onItemSelectedListener
,它有两个回调方法:
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
和public void onNothingSelected(AdapterView<?> parent)
方法注解可以用来绑定到这些方法中的任何一个.
每一个注解有一个默认的callback,指定它绑定到什么方法上;可以通过callback参数指定为一个特定的方法.
@OnItemSelected(R.id.spinner)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.spinner, callback = OnItemSelected.Callback.NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
需要注意的是Spinner中只要有数据,默认都会选中第0个数据,所以想进入到onNothingSelected()方法,就需要把Adapter中的数据都清空.
⑨更加简单的findViewById
ButterKnife.findById()
可以用来获取Activity,Dialog或View中的任何View.
ButterKnife自动完成了类型转换,所以获取出来以后不用进行显式强转,直接赋值给具体的View类型引用即可.
总结
以上就是ButterKnife全部的比较常用的使用方法!
想要了解它的实现原理的,当然是要看源码啦!推荐一下下面的两篇文章,可以参考一下:
深入理解ButterKnife源码并掌握原理(一)
这是一个系列的文章,讲解的比较详细,涉及的内容也比较多!最后还有自己根据原理写的一个相似的demo,可以看一下!
参考文章:
ButterKnife基本使用
ButterKnife使用详解
Android Butter Knife 框架——最好用的View注入