加入到项目的方法
把这块放到最前是有原因的,下面是方法:
MAVEN项目:(7.0.1是本文当前版本号)(在pom.xml文件中)
<dependency><groupId>com.jakewharton</groupId><artifactId>butterknife</artifactId><version>7.0.1</version></dependency>
Gradle项目(现在Android应该都是Gradle了吧,在build.gradle文件中)
compile 'com.jakewharton:butterknife:7.0.1'
另外,还需要下面两个配置:
//支持lint warning 检查机制lintOptions {disable 'InvalidPackage'}//为什么加入这个呢?防止冲突,比如我同时用了dagger-compiler就会报错,说下面这个`Processor`重复了packagingOptions {exclude 'META-INF/services/javax.annotation.processing.Processor'}
这样加入了还没有完,我们还要在Proguard中加入下面这些代码(为什么呢?Proguard的原理大家如果懂的话就知道了,Butterknife的使用和生成的一些类都是动态的,而ProGuard这样的工具可能判定这些类没有被使用而移除他们,所以要在他的配置文件下面做下面的配置):
-keep class butterknife.** { *; }-dontwarn butterknife.internal.**-keep class **$$ViewBinder { *; }-keepclasseswithmembernames class * {@butterknife.* <fields>;}-keepclasseswithmembernames class * {@butterknife.* <methods>;}
最简单的用法
最简单的肯定是自动关联View了,以前我们都是样板式的代码:
private Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn=(Button)findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "Btn Clicked", Toast.LENGTH_SHORT).show();}});}
后来有了ButterKnife就简单了,如下:
class ExampleActivity extends Activity {@Bind(R.id.title) Button btn;@Override public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);// TODO Use fields...}}
没有一堆的findViewById和强制转换是不是清爽多了呢?
而且,即使这些代码,都可以通过Android Studio的插件Android
ButterKnife Zelezny帮你完成了。
ButterKnife可不是通过反射实现了,而是在编译的时候生成的代码,和我们自己写的其实原理一样,比如上面的Button的绑定的实现就类似下面的方法:
public void bind(ExampleActivity activity) {activity.btn = (android.widget.Button) activity.findViewById(2130968578);}ButterKnife以前绑定的代码是
@InjectView注解和inject方法,现在改了名字感觉更容易理解了,基本原理没变。- 另外,大家关心
@Bind注解对于绑定的成员变量有没有要求呢?其实是有的,如果你试着将它的限定符改为private,在编译的时候就会报错如下:
Error:(21, 20) 错误: @Bind fields must not be private or static. ...也就是你的成员变量不能是private 或者static修饰了。
是不是和我们自己写的代码差不多呢?
更多的绑定
绑定资源
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的绑定
比如说Fragment中(得到View,然后bind方法传入这个View的实例):
public class FancyFragment extends Fragment {@Bind(R.id.button1) Button button1;@Bind(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;}}
在Adapter中的用法
经常会在Adapter中使用ViewHolder,其实你也可以在ViewHolder中使用ButterKnife:
在ViewHolder的构造函数中调用bind,然后成员变量同样的使用@Bind注解。其实这几种绑定原理都一样,就是我们前面编译后的代码那样的方式。
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 {@Bind(R.id.title) TextView name;@Bind(R.id.job_title) TextView jobTitle;public ViewHolder(View view) {ButterKnife.bind(this, view);}}}
ButterKnife.bind()还有其他的一些API,可以自己关注一下,直接看源码的注释很容易理解了。
View List批量操作
如果我们有一系列的View放到了一个List里面,就可以进行批量操作了:批量绑定,批量设置属性等。
//批量绑定@Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })List<EditText> nameViews;
//批量设置ButterKnife.apply(nameViews, DISABLE);ButterKnife.apply(nameViews, ENABLED, false);
其中,DIABLE,ENABLED是我们定义的两个对象,一个是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);}};
也就是第一个apply将所有的nameViews中的View对象设置为disabled,第二个apply将所有的对象的enable属性设置为false(第三个参数)
另外,我们可以直接对属性进行设置,而不需要编写Action和Setter,例如:
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
绑定监听器
ButterKnife还有一个比较常用的功能就是类似@OnClick等的绑定监听器的方法,Android中需要大量的监听器监听用户的操作。示例如下:
@OnClick(R.id.submit)public void submit(View view) {// TODO submit data to server...}
如果不需要绑定的对象,不写也可以:
@OnClick(R.id.submit)public void submit() {// TODO submit data to server...}
而且,这里可以直接将绑定的实例转换成实际的对象:
@OnClick(R.id.submit)public void sayHi(Button button) {button.setText("Hello!");}
另外,多个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 {@OnClickpublic void onClick() {// TODO do something!}}
这样,用户点击FancyButton时就会触发该方法。
绑定重置
我们可能需要在Fragment销毁的时候将绑定的View全部设置为null,ButterKnife提供了一个unbind方法自动执行这个操作。
public class FancyFragment extends Fragment {@Bind(R.id.button1) Button button1;@Bind(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;}@Override public void onDestroyView() {super.onDestroyView();ButterKnife.unbind(this);}}
可选的绑定
如果你给一个绑定添加了一个@Nullable注解,即使对应的资源id不存在也不会报错。有时候我们不能保证这个id一定存在,或者有特殊的需求的时候可以使用
@Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere;@Nullable @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {// TODO ...}
多方法监听
例如ListView的设置onItemOnItemSelected的SelectedListener接口有两个回调方法,一个是onItemSelected,一个是onNothingSelected,这时候,我们可以设置两个注解来分别处理这两个回调方法:
@OnItemSelected(R.id.list_view)void onItemSelected(int position) {// TODO ...}@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)void onNothingSelected() {// TODO ...}
小工具
如果你不想用注解的方法绑定View但是又很讨厌强制转换,就可以用ButterKnife.findById(id)这样的方法:
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);
其实这个方法你自己实现也只需要非常简单的代码,就是使用泛型,例如我自己定义一个静态的工具类Views.java,他的代码如下:
public class Views {public static <T> T findById(Activity context, int id) {return (T) context.findViewById(id);}}//其他的方法也类似
本文介绍ButterKnife库的基本用法,包括如何在Maven和Gradle项目中引入依赖,以及如何使用ButterKnife简化Android项目的视图绑定、监听器绑定等常见任务。
916

被折叠的 条评论
为什么被折叠?



