加入到项目的方法

把这块放到最前是有原因的,下面是方法: 
MAVEN项目:(7.0.1是本文当前版本号)(在pom.xml文件中)

            
  1. com.jakewharton
  2. butterknife
  3. 7.0.1

Gradle项目(现在Android应该都是Gradle了吧,在build.gradle文件中)

            
  1. compile 'com.jakewharton:butterknife:7.0.1'

另外,还需要下面两个配置:

            
  1. //支持lint warning 检查机制
  2. lintOptions {
  3. disable 'InvalidPackage'
  4. }
  5. //为什么加入这个呢?防止冲突,比如我同时用了dagger-compiler就会报错,说下面这个`Processor`重复了
  6. packagingOptions {
  7. exclude 'META-INF/services/javax.annotation.processing.Processor'
  8. }

这样加入了还没有完,我们还要在Proguard中加入下面这些代码(为什么呢?Proguard的原理大家如果懂的话就知道了,Butterknife的使用和生成的一些类都是动态的,而ProGuard这样的工具可能判定这些类没有被使用而移除他们,所以要在他的配置文件下面做下面的配置):

            
  1. -keep class butterknife.** { *; }
  2. -dontwarn butterknife.internal.**
  3. -keep class **$$ViewBinder { *; }
  4. -keepclasseswithmembernames class * {
  5. @butterknife.* ;
  6. }
  7. -keepclasseswithmembernames class * {
  8. @butterknife.* ;
  9. }

最简单的用法

最简单的肯定是自动关联View了,以前我们都是样板式的代码:

            
  1. private Button btn;
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. btn=(Button)findViewById(R.id.btn);
  7. btn.setOnClickListener(new View.OnClickListener() {
  8. @Override
  9. public void onClick(View v) {
  10. Toast.makeText(MainActivity.this, "Btn Clicked", Toast.LENGTH_SHORT).show();
  11. }
  12. });
  13. }

后来有了ButterKnife就简单了,如下:

            
  1. class ExampleActivity extends Activity {
  2. @Bind(R.id.title) Button btn;
  3. @Override public void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. ButterKnife.bind(this);
  7. // TODO Use fields...
  8. }
  9. }

没有一堆的findViewById和强制转换是不是清爽多了呢? 
而且,即使这些代码,都可以通过Android Studio的插件Android ButterKnife Zelezny帮你完成了。

  1. ButterKnife可不是通过反射实现了,而是在编译的时候生成的代码,和我们自己写的其实原理一样,比如上面的Button的绑定的实现就类似下面的方法:

                            
    1. public void bind(ExampleActivity activity) {
    2. activity.btn = (android.widget.Button) activity.findViewById(2130968578);
    3. }
  2. ButterKnife以前绑定的代码是@InjectView注解和inject方法,现在改了名字感觉更容易理解了,基本原理没变。

  3. 另外,大家关心@Bind注解对于绑定的成员变量有没有要求呢?其实是有的,如果你试着将它的限定符改为private,在编译的时候就会报错如下: 
                            
    1. Error:(21, 20) 错误: @Bind fields must not be private or static. ...

也就是你的成员变量不能是private 或者static修饰了。

是不是和我们自己写的代码差不多呢?

更多的绑定

绑定资源

            
  1. class ExampleActivity extends Activity {
  2. @BindString(R.string.title) String title;
  3. @BindDrawable(R.drawable.graphic) Drawable graphic;
  4. @BindColor(R.color.red) int red; // int or ColorStateList field
  5. @BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field
  6. // ...
  7. }
  1. 绑定其他的资源类似,应该不需要一一列举了吧
  2. 不过有时候资源不需要搞成成员变量吧?自己选择吧

非Activity的绑定

比如说Fragment中(得到View,然后bind方法传入这个View的实例):

            
  1. public class FancyFragment extends Fragment {
  2. @Bind(R.id.button1) Button button1;
  3. @Bind(R.id.button2) Button button2;
  4. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  5. View view = inflater.inflate(R.layout.fancy_fragment, container, false);
  6. ButterKnife.bind(this, view);
  7. // TODO Use fields...
  8. return view;
  9. }
  10. }

在Adapter中的用法

经常会在Adapter中使用ViewHolder,其实你也可以在ViewHolder中使用ButterKnife: 
在ViewHolder的构造函数中调用bind,然后成员变量同样的使用@Bind注解。其实这几种绑定原理都一样,就是我们前面编译后的代码那样的方式。

            
  1. public class MyAdapter extends BaseAdapter {
  2. @Override public View getView(int position, View view, ViewGroup parent) {
  3. ViewHolder holder;
  4. if (view != null) {
  5. holder = (ViewHolder) view.getTag();
  6. } else {
  7. view = inflater.inflate(R.layout.whatever, parent, false);
  8. holder = new ViewHolder(view);
  9. view.setTag(holder);
  10. }
  11. holder.name.setText("John Doe");
  12. // etc...
  13. return view;
  14. }
  15. static class ViewHolder {
  16. @Bind(R.id.title) TextView name;
  17. @Bind(R.id.job_title) TextView jobTitle;
  18. public ViewHolder(View view) {
  19. ButterKnife.bind(this, view);
  20. }
  21. }
  22. }

ButterKnife.bind()还有其他的一些API,可以自己关注一下,直接看源码的注释很容易理解了。

View List批量操作

如果我们有一系列的View放到了一个List里面,就可以进行批量操作了:批量绑定,批量设置属性等。

            
  1. //批量绑定
  2. @Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })
  3. List<EditText> nameViews;
            
  1. //批量设置
  2. ButterKnife.apply(nameViews, DISABLE);
  3. ButterKnife.apply(nameViews, ENABLED, false);

其中,DIABLE,ENABLED是我们定义的两个对象,一个是Action,负责执行操作,一个是Setter,负责将值设置为第三个参数:

            
  1. static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
  2. @Override public void apply(View view, int index) {
  3. view.setEnabled(false);
  4. }
  5. };
  6. static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
  7. @Override public void set(View view, Boolean value, int index) {
  8. view.setEnabled(value);
  9. }
  10. };

也就是第一个apply将所有的nameViews中的View对象设置为disabled,第二个apply将所有的对象的enable属性设置为false(第三个参数)

另外,我们可以直接对属性进行设置,而不需要编写ActionSetter,例如:

            
  1. ButterKnife.apply(nameViews, View.ALPHA, 0.0f);

绑定监听器

ButterKnife还有一个比较常用的功能就是类似@OnClick等的绑定监听器的方法,Android中需要大量的监听器监听用户的操作。示例如下:

            
  1. @OnClick(R.id.submit)
  2. public void submit(View view) {
  3. // TODO submit data to server...
  4. }

如果不需要绑定的对象,不写也可以:

            
  1. @OnClick(R.id.submit)
  2. public void submit() {
  3. // TODO submit data to server...
  4. }

而且,这里可以直接将绑定的实例转换成实际的对象:

            
  1. @OnClick(R.id.submit)
  2. public void sayHi(Button button) {
  3. button.setText("Hello!");
  4. }

另外,多个View也可以绑定到一个处理方法上:

            
  1. @OnClick({ R.id.door1, R.id.door2, R.id.door3 })
  2. public void pickDoor(DoorView door) {
  3. if (door.hasPrizeBehind()) {
  4. Toast.makeText(this, "You win!", LENGTH_SHORT).show();
  5. } else {
  6. Toast.makeText(this, "Try again", LENGTH_SHORT).show();
  7. }
  8. }

如果是自定义的View,可以直接绑定到他自己的处理方法上而不需要指定ID

            
  1. public class FancyButton extends Button {
  2. @OnClick
  3. public void onClick() {
  4. // TODO do something!
  5. }
  6. }

这样,用户点击FancyButton时就会触发该方法。

绑定重置

我们可能需要在Fragment销毁的时候将绑定的View全部设置为null,ButterKnife提供了一个unbind方法自动执行这个操作。

            
  1. public class FancyFragment extends Fragment {
  2. @Bind(R.id.button1) Button button1;
  3. @Bind(R.id.button2) Button button2;
  4. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  5. View view = inflater.inflate(R.layout.fancy_fragment, container, false);
  6. ButterKnife.bind(this, view);
  7. // TODO Use fields...
  8. return view;
  9. }
  10. @Override public void onDestroyView() {
  11. super.onDestroyView();
  12. ButterKnife.unbind(this);
  13. }
  14. }

可选的绑定

如果你给一个绑定添加了一个@Nullable注解,即使对应的资源id不存在也不会报错。有时候我们不能保证这个id一定存在,或者有特殊的需求的时候可以使用

            
  1. @Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere;
  2. @Nullable @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
  3. // TODO ...
  4. }

多方法监听

例如ListView的设置onItemOnItemSelectedSelectedListener接口有两个回调方法,一个是onItemSelected,一个是onNothingSelected,这时候,我们可以设置两个注解来分别处理这两个回调方法:

            
  1. @OnItemSelected(R.id.list_view)
  2. void onItemSelected(int position) {
  3. // TODO ...
  4. }
  5. @OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
  6. void onNothingSelected() {
  7. // TODO ...
  8. }

小工具

如果你不想用注解的方法绑定View但是又很讨厌强制转换,就可以用ButterKnife.findById(id)这样的方法:

            
  1. View view = LayoutInflater.from(context).inflate(R.layout.thing, null);
  2. TextView firstName = ButterKnife.findById(view, R.id.first_name);
  3. TextView lastName = ButterKnife.findById(view, R.id.last_name);
  4. ImageView photo = ButterKnife.findById(view, R.id.photo);

其实这个方法你自己实现也只需要非常简单的代码,就是使用泛型,例如我自己定义一个静态的工具类Views.java,他的代码如下:

            
  1. public class Views {
  2. public static <T> T findById(Activity context, int id) {
  3. return (T) context.findViewById(id);
  4. }
  5. }
  6. //其他的方法也类似

更多相关文章

  1. 面试题及答案
  2. Android事件分发机制的探索与发现之ViewGroup篇
  3. Android(安卓)listview增加条目时自动回滚到最后一行
  4. 关于Android(安卓)Fragment生命周期以及其他方法的调用执行顺序
  5. Android(安卓)动态创建Drawable selector
  6. Android底层字符传递给上层应用举例
  7. Android(安卓)View的onClick回调机制
  8. 加快Android(安卓)Stduio编译速度方法之一
  9. Android的ViewPager中移除Fragment

随机推荐

  1. Android电话拨打流程源码分析
  2. 为什么说Android令人沮丧!?
  3. Android状态check、focused、pressed、se
  4. Android安装以及Eclipse插件(Google Andr
  5. Ubuntu 试用Android(安卓)L版本
  6. android 10 高通 图标名称双行显示
  7. Android收藏商品/关注商品
  8. android开源新闻小程序、3D翻转公告效果
  9. 记-Android(安卓)studio使用的小疑惑
  10. vs2015 支持Android(安卓)arm neon Intro