一篇文章玩转ButterKnife,让代码更简洁

前言

话说,Android开发的兄弟们都知道,每次初始化控件,设置相应的事件,写的那点过程多而且恶心。我们先一块回顾下不堪的曾经~那些年,我们是这样初始化控件:


  1. // 每次的习惯上来写一个initView()方法 
  2. tvContent = (TextView) findViewById(R.id.btn_content); 
  3. // 遇到项目大的时候,这里面的东西,也曾占据半壁江山。。。苦不堪言 
  4. // 当然也曾封装过方法,避免各种findViewById,但是依旧如此。。。  

那些年,我们是这样设置事件:


  1. tvContent.setOnClickListener(this); 
  2. // 当然,LZ的习惯依旧扔到initView中,让他们尽情的浪荡,放纵~  

But,骚年,身为一个Android开发,你还能继续忍受这种不堪的摧残么?答案当然不能!

那么,接下来为大家带来一个神器,助我们开发高效,快捷~

ButterKnife 初识

ButterKnife,又被戏称为黄油刀,至于为什么被戏称为这个,大家可以看下面附上的从官方截取的icon~

一块桌布,一个盘子,一个Android小机器人形状的黄油,一把刀。这些合起来被大家戏称为黄油刀。(我说呢,纠结我半天,都搞不懂黄油刀是个什么鬼,这次晓得了)icon下面简单解释就是为Android 视图(View)提供绑定字段和方法。 也就是说,我们今后可以通过这把刀去替换之前琐碎的初始化~

大家有兴趣的也可以去官网上看看,下面为大家附上官网地址以及GitHub地址捎带的附带个api地址。

官方地址:http://jakewharton.github.io/butterknife/

GitHub地址:https://github.com/JakeWharton/butterknife

API访问地址:http://jakewharton.github.io/butterknife/javadoc/

话说,简单了解之后,还是来点干货吧~不然说不过去哈

首先我们要明白,ButterKnife 是出自Android大神JakeWharton之手的一个开源库,它的作用就是通过注解绑定视图的方法,从而简化代码量(减少我们当年findViewById以及设置事件时编写的大量代码)。

而我们使用一个东西,必须要知道他的优势在哪儿?我用它能给我带来什么方便之处?那么接下来,我们看看这把“黄油刀”有着什么样的优势,从而能简化我们一些代码?

ButterKnife 优势

1. 强大的View绑定,Click事件处理功能以及资源内容,简化代码,提升开发效率;

2. 方便的处理Adapter里的ViewHolder绑定问题;

3. 运行时不会影响APP效率,使用配置方便;

4. 代码清晰,可读性强。

了解完ButterKnife优势后,怀着好奇心,我们看看他都支持哪儿些方面,换句话说就是,我们开发过程中,在什么情况下可以通过使用ButterKnife去减少我们曾经的代码量?

ButterKnife 使用场景

  • View(视图)绑定:例如初始化控件;
  • 资源绑定:例如color,string等;
  • 非Activity绑定:这里值得是当时用 fragment 的时候;
  • View List 绑定: Adapter 中 ViewHolder,具体使用会在下方讲解;
  • Listener 绑定:这个就好理解了,也就是平时控件所需监听事件。

ButterKnife 语法

1. activity fragment 绑定与 fragment解绑

想要使用ButterKnife,简单配置之后,我们还需要在Activity中onCreate()绑定,如下:


  1. @Override 
  2.     protected void onCreate(Bundle savedInstanceState) { 
  3.         super.onCreate(savedInstanceState); 
  4.         setContentView(R.layout.activity_main); 
  5.         // 必须在setContentView()之后绑定 
  6.         ButterKnife.bind(this);  
  7.     }  

而如果使用fragment,官方给出的绑定以及解绑如下:


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

绑定之后,我们一起来看看,常用的几种监听通过使用ButterKnife之后,我们又该如何编写相关事件呢?别急,往下看~

2.单击事件

首先我们先看看人家表层提供我们代码中,我们可以得到哪儿些对我们有用的信息

首先明确,targetType(目标类型)为View,setter为setOnClickListener(单击事件监听),type为ButterKnife封装的单击事件(butterknife.internal.DebouncingOnClickListener),而method中则是name为doClick以及parameters为View类型的俩个参数;而下面的interface接口中需要我们传递一个id。

简单了解后,我们衍生出三种写法,如下:


  1. // 写法1 
  2.    @OnClick(控件ID) 
  3.    void 方法名() { 
  4.        //业务逻辑操作 
  5.    } 
  6.     
  7.    // 写法2 
  8.    @OnClick(控件ID) 
  9.    void 方法名(控件类型) { 
  10.        //业务逻辑操作 
  11.    } 
  12.     
  13.    // 写法3 
  14.    @OnClick(控件ID) 
  15.    void 方法名(View view) { 
  16.        //业务逻辑操作 
  17.    }  

你可以按照上面指定一个个的写,也可以绑定多个,如官网提供下面写法:

3.长按事件

同样依旧看人家怎么写的,看看我们能了解到什么

和单击事件对比,长按时间则多出了一个returnType(返回值),且默认为false。So,写法如下~


  1. // 方法1 
  2.    boolean 方法名(){ 
  3.        // 业务逻辑操作 
  4.        return false; 
  5.    } 
  6.     
  7.    // 方法2 
  8.    boolean 方法名(控件类型){ 
  9.        // 业务逻辑操作 
  10.        return false; 
  11.    } 
  12.  
  13.    // 方法3 
  14.    boolean 方法名(View view){ 
  15.        // 业务逻辑操作 
  16.        return false; 
  17.    }  

4.Checked改变事件

老规矩:

改变,一般来说,会提供我们一个标识,去方便我们根据不同的状态去处理不同的逻辑,so...


  1. // 写法1 
  2.     @OnCheckedChanged(控件ID) 
  3.     void radioButtonCheckChange(boolean isl) { 
  4.         // 业务逻辑 
  5.     } 
  6.      
  7.     // 写法2 
  8.     @OnCheckedChanged(控件ID) 
  9.     void radioButtonCheckChange(控件类型,boolean isl) { 
  10.         // 业务逻辑 
  11.     }  

5.监听软键盘右下角按钮事件

老规矩:

so...经过上面几个大家可以知道,我们只需要对parameters以及是否是returnType重点关注即可。


  1. // 写法1 
  2.     @OnEditorAction(控件ID) 
  3.     boolean 方法名() { 
  4.         // 业务逻辑操作 
  5.         return false; 
  6.     } 
  7.  
  8.     // 写法2 
  9.     // code:状态码 
  10.     @OnEditorAction(控件ID) 
  11.     boolean EditTextAction(int code) { 
  12.         // 业务逻辑操作 
  13.         return false; 
  14.     } 
  15.  
  16.     // 写法3 
  17.     // KeyEvent 
  18.     @OnEditorAction(控件ID) 
  19.     boolean EditTextAction(KeyEvent keyEvent) { 
  20.         // 业务逻辑操作 
  21.         return false; 
  22.     } 
  23.  
  24.     // 写法4 
  25.     @OnEditorAction(控件ID) 
  26.     boolean EditTextAction(int code, KeyEvent keyEvent) { 
  27.         // 业务逻辑操作 
  28.         return false; 
  29.     } 
  30.  
  31.     // 写法5 
  32.     @OnEditorAction(控件ID) 
  33.     boolean EditTextAction(TextView textView,int code, KeyEvent keyEvent) { 
  34.         // 业务逻辑操作 
  35.         return false; 
  36.     }  

6. EditText内容改变监听事件

由于源码中内容较长,不方便截图,故截取部分代码做解析,如下:


  1. @Target(METHOD) 
  2. @Retention(CLASS) 
  3. @ListenerClass( 
  4.     targetType = "android.widget.TextView", 
  5.     setter = "addTextChangedListener", 
  6.     remover = "removeTextChangedListener", 
  7.     type = "android.text.TextWatcher",   --->   这里同样对之前的TextWatcher做了相关处理 ggg 
  8.     callbacks = OnTextChanged.Callback.class   --->   自定义枚举,通过枚举类型标识当前操作 666 
  9. public @interface OnTextChanged { 
  10.   /** View IDs to which the method will be bound. */ 
  11.   @IdRes int[] value() default { View.NO_ID };   --->   需要传入ID 
  12.  
  13.   /** Listener callback to which the method will be bound. */ 
  14.   Callback callback() default Callback.TEXT_CHANGED;  --->  未改变状态 
  15.  
  16.   /** {@link TextWatcher} callback methods. */ 
  17.   enum Callback {  --->  枚举中分为三种类似 未改变 改变前 改变后 
  18.     /** {@link TextWatcher#onTextChanged(CharSequence, int, int, int)} */ 
  19.     @ListenerMethod( 
  20.         name = "onTextChanged",  --->  当前标识为 未改变 
  21.         parameters = { 
  22.             "java.lang.CharSequence",  --->  用户输入字符 
  23.             "int", --->  改变前个数 
  24.             "int", --->  测试时,返回0,没整明白代表什么意思 
  25.             "int"  --->  根据打印结果,猜测这个应该是每次增加内容个数 
  26.         } 
  27.     ) 
  28.     TEXT_CHANGED, 
  29.  
  30.     /** {@link TextWatcher#beforeTextChanged(CharSequence, int, int, int)} */ 
  31.     @ListenerMethod( 
  32.         name = "beforeTextChanged",  --->  当前标识为 改变前 
  33.         parameters = { 
  34.             "java.lang.CharSequence",  --->  用户输入字符 
  35.             "int", --->  改变前个数 
  36.             "int", 
  37.             "int" 
  38.         } 
  39.     ) 
  40.     BEFORE_TEXT_CHANGED, 
  41.  
  42.     /** {@link TextWatcher#afterTextChanged(android.text.Editable)} */ 
  43.     @ListenerMethod( 
  44.         name = "afterTextChanged",  --->  当前标识为 改变后 
  45.         parameters = "android.text.Editable"  --->  用户输入字符 
  46.     ) 
  47.     AFTER_TEXT_CHANGED, --->  我们关注的重点在此,每次只需要监听这个,去做相关处理即可 
  48.   }  

从上得知,关于EditText内容改变事件,我们关注点只在乎改变后的内容格式(个数)是否符合项目需求,而其他可以暂时忽略,从而衍生下面写法:


  1. // 内容改变后监听 
  2.     // Editable editable:用户输入字符 
  3.     @OnTextChanged(value = 控件ID, callback = 监听类型,改变后取值为:OnTextChanged.Callback.AFTER_TEXT_CHANGED) 
  4.     void editTextChangeAfter(Editable editable) { 
  5.         // 业务逻辑 
  6.     } 
  7.  
  8.     // 内容改变前监听 
  9.     @OnTextChanged(value = 控件ID, callback = 监听类型,改变前取值为:OnTextChanged.Callback.BEFORE_TEXT_CHANGED) 
  10.     void editTextChangeBefore(CharSequence s, int start) { 
  11.         // 业务逻辑 
  12.     } 
  13.  
  14.     // 内容未发生改变监听 
  15.     @OnTextChanged(value = 控件ID, callback = 监听类型,取值为:OnTextChanged.Callback.TEXT_CHANGED) 
  16.     void editTextChange(CharSequence s, int start) { 
  17.         // 业务逻辑 
  18.     }  

7. 焦点监听事件

老规矩:

由此可见,如下:


  1. @OnFocusChange(控件ID) 
  2.     void editTextFocus(boolean isl){ 
  3.         // 业务逻辑 
  4.     }  

8. 触摸监听事件

老规矩:

写法如下:


  1. @OnTouch(控件ID) 
  2.     boolean imageView(MotionEvent event){ 
  3.         // 业务逻辑 
  4.         return false; 
  5.     }  

9. item项单击监听事件

老规矩:

 

so...


  1. @OnItemClick(控件ID) 
  2.     void listItemClick(int position){ 
  3.         // 业务逻辑 
  4.     }  

10. item项长按监听事件

老规矩:

so...


  1. @OnItemLongClick(R.id.listView) 
  2.     boolean listItemLongClick(int position) { 
  3.         Toast.makeText(this, "OnItemLongClick---点击了第" + position + "个", Toast.LENGTH_SHORT).show(); 
  4.         return true; 
  5.     } 

ButterKnife 使用注意

1.Activity ButterKnife.bind(this) 必须在 setContentView() 之后,且父类 bind 绑定后,子类不需要再 bind;

2.Fragment 中使用需要传入view:Fragment ButterKnife.bind(this, mRootView);

3.属性布局不能用private or static 修饰,否则会报错;

4.setContentView()不能通过注解实现。(其他的有些注解框架可以)

通过上面简单介绍,相信大家对这把刀已经有了一个初步的理解,那么如何在Android Studio中通过使用这把刀从而改善我们的代码呢?我们接着往下瞧。

Android Studio使用ButterKnife前期准备操作

想要在Android Studio中使用ButterKnife,首先需要下载安装ButterKnife插件,之后经过简单配置之后方可使用~

第一步:Android Studio集成ButterKnife插件

1.点击 File ---> Settings... ---> 选择 Plugins(也可以使用<font color=#FF0000>快捷键 Ctrl+Alt+S)

2.输入ButterKnife,选择“Android ButterKnife Zelezny”,点击安装(LZ这里已经安装好了),稍后Android Studio会提示重启AS,确认即可。

3.经过以上简单俩步,我们的Android Studio又get了新技能,那就是:支持ButterKnife插件!

第二步:配置ButterKnife

1.使用前,我们需要对ButterKnife进行简单配置( 为我们的项目引入'com.jakewharton:butterknifecompiler:8.5.1','com.jakewharton:butterknife:8.5.1' ),引入过程如下所示:

 

2.引入完成之后,我们先来小试牛刀~得瑟得瑟

在MainActivity中的onCreate 右键layout,选择Generate... ,Generate ButterKnife Injections,选择要使用注解的控件,点击Confirm

一键可视化操作,方便快捷~进过上面的配置后,我们可以在项目中尽情的使用ButterKnife各种秀了~

刀法一部曲,玩转常用事件监听

1.在MainActivity布局中新增几个常用控件,通过右键layout,选择Generate... ,Generate ButterKnife Injections,选择要使用注解的控件,点击Confirm ,从而生成我们接下来演示根本(后面会有所更改),如下图所示~

 

接下来为大家演示相关事件使用,一点点玩转黄油刀

1. 单击事件(以TextView为例)

代码如下:


  1. @OnClick(R.id.text) 
  2.     void textClick() { 
  3.         Toast.makeText(MainActivity.this, "TextView的单击事件触发。。。(无参-默认)", Toast.LENGTH_SHORT).show(); 
  4.     } 
  5.  
  6.     @OnClick(R.id.text) 
  7.     void textClick(TextView textView){ 
  8.         Toast.makeText(MainActivity.this, "TextView的单击事件触发。。。(TextView)", Toast.LENGTH_SHORT).show(); 
  9.     } 
  10.  
  11.     @OnClick(R.id.text) 
  12.     void textClick(View view){ 
  13.         Toast.makeText(MainActivity.this, "TextView的单击事件触发。。。(View)", Toast.LENGTH_SHORT).show(); 
  14.     } 

运行结果展示:

2. 长按事件(以Button为例)

代码如下:


  1. @OnLongClick(R.id.button) 
  2.     boolean buttonLongClick(){ 
  3.         Toast.makeText(MainActivity.this, "Button的长按事件触发。。。(无参-默认)", Toast.LENGTH_SHORT).show(); 
  4.         return false; 
  5.     } 
  6.  
  7. //    @OnLongClick(R.id.button) 
  8. //    boolean buttonLongClick(Button button){ 
  9. //        Toast.makeText(MainActivity.this, "Button的长按事件触发。。。(TextView)", Toast.LENGTH_SHORT).show(); 
  10. //        return false; 
  11. //    } 
  12.  
  13. //    @OnLongClick(R.id.button) 
  14. //    boolean buttonLongClick(View view){ 
  15. //        Toast.makeText(MainActivity.this, "Button的长按事件触发。。。(View)", Toast.LENGTH_SHORT).show(); 
  16. //        return false; 
  17. //    } 

运行结果如下:

这里大家可能会问了,LZ你干嘛要把下面的注释掉了呢,是不是不能用呢?确实,一开始没有注释,运行时候出现异常,提示如下:


  1. Multiple listener methods with return value specified for ID:2131165193 

LZ理解为,这个监听只会为ID(2131165193)返回相应监听,也就是一一对应!so... 一山不容二虎,除非一公一母啊~

3. Checked改变事件(以CheckBox为例)

代码如下:


  1. @OnCheckedChanged(R.id.checkBox) 
  2.     void radioButtonCheckChange(boolean isl) { 
  3.         Toast.makeText(MainActivity.this, "CheckBox。。。(无参)" + isl, Toast.LENGTH_SHORT).show(); 
  4.     } 
  5.  
  6.     @OnCheckedChanged(R.id.checkBox) 
  7.     void radioButtonCheckChange(CheckBox checkBox,boolean isl) { 
  8.         Toast.makeText(MainActivity.this, "CheckBox。。。(CheckBox)" + isl, Toast.LENGTH_SHORT).show(); 
  9.     } 

运行结果如下:

 

4. 监听软键盘右下角按钮事件

代码如下:


  1. //    @OnEditorAction(R.id.tv_editor_action) 
  2. //    boolean EditTextAction() { 
  3. //        Toast.makeText(MainActivity.this, " 点击---通往天堂 无参", Toast.LENGTH_SHORT).show(); 
  4. //        return false; 
  5. //    } 
  6.  
  7. //    @OnEditorAction(R.id.tv_editor_action) 
  8. //    boolean EditTextAction(int code) { 
  9. //        Toast.makeText(MainActivity.this, " 点击---通往天堂 code:"+code, Toast.LENGTH_SHORT).show(); 
  10. //        return false; 
  11. //    } 
  12.  
  13. //    @OnEditorAction(R.id.tv_editor_action) 
  14. //    boolean EditTextAction(KeyEvent keyEvent) { 
  15. //        Toast.makeText(MainActivity.this, "点击---通往天堂 KeyEvent:"+keyEvent, Toast.LENGTH_SHORT).show(); 
  16. //        return false; 
  17. //    } 
  18.  
  19. //    @OnEditorAction(R.id.tv_editor_action) 
  20. //    boolean EditTextAction(int code, KeyEvent keyEvent) { 
  21. //        Toast.makeText(MainActivity.this, "点击---通往天堂 code:"+code+" KeyEvent:"+keyEvent, Toast.LENGTH_SHORT).show(); 
  22. //        return false; 
  23. //    } 
  24.  
  25.     @OnEditorAction(R.id.tv_editor_action) 
  26.     boolean EditTextAction(TextView textView,int code, KeyEvent keyEvent) { 
  27.         Toast.makeText(MainActivity.this, textView.getText().toString()+" 点击---通往天堂 code:"+code+" KeyEvent:"+keyEvent, Toast.LENGTH_SHORT).show(); 
  28.         return false; 
  29.     } 

运行效果下:

5. EditText内容改变监听事件

代码如下:


  1. @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) 
  2.     void editTextChangeAfter(Editable editable) { 
  3.         Toast.makeText(MainActivity.this, "改变后内容为:"+editable.toString(), Toast.LENGTH_SHORT).show(); 
  4.         System.out.println("改变后---内容为:"+editable.toString()); 
  5.     } 
  6.  
  7.     @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.BEFORE_TEXT_CHANGED) 
  8.     void editTextChangeBefore(CharSequence s, int start, int before, int count) { 
  9.         Toast.makeText(MainActivity.this, "编辑内容为:"+s+",开始前个数:"+start, Toast.LENGTH_SHORT).show(); 
  10.         System.out.println("改变前---内容为:"+s+",开始前个数:"+start+",:"+before+","+count); 
  11.     } 
  12.  
  13.     @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.TEXT_CHANGED) 
  14.     void editTextChange(CharSequence s, int start, int before, int count) { 
  15.         Toast.makeText(MainActivity.this, "编辑内容为:"+s+",开始前个数:"+start, Toast.LENGTH_SHORT).show(); 
  16.         System.out.println("未编辑---内容为:"+s+",开始前个数:"+start+","+before+","+count); 
  17.     } 

运行结果如下:

6.焦点监听事件

代码如下:


  1. @OnFocusChange(R.id.editTextFocus) 
  2.     void editTextFocus(boolean isl) { 
  3.         if (isl) { 
  4.             Toast.makeText(MainActivity.this, "获取焦点" + isl, Toast.LENGTH_SHORT).show(); 
  5.         } else { 
  6.             Toast.makeText(MainActivity.this, "失去焦点" + isl, Toast.LENGTH_SHORT).show(); 
  7.         } 
  8.     } 

运行结果如下:

 

7. 触摸监听事件

代码如下:


  1. @OnTouch(R.id.imageView) 
  2.     boolean imageView(MotionEvent event){ 
  3.         System.out.println(event); 
  4.         return false; 
  5.     } 

运行结果如下:


  1. 04-10 11:47:04.504 32627-32627/cn.hlq.butterknifestudyI/System.out: MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=189.8265, y[0]=148.42676, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=6743683, downTime=6743683, deviceId=1, source=0x1002 } 

8. item单击以及长按监听事件

代码如下:


  1. @OnItemClick(R.id.listView) 
  2.   void listItemClick(int position){ 
  3.       Toast.makeText(this,"OnItemClick---点击了第"+position+"个",Toast.LENGTH_SHORT).show(); 
  4.   } 
  5.  
  6.   @OnItemLongClick(R.id.listView) 
  7.   boolean listItemLongClick(int position) { 
  8.       Toast.makeText(this, "OnItemLongClick---点击了第" + position + "个", Toast.LENGTH_SHORT).show(); 
  9.       return true; 
  10.   } 

运行结果如下:

想必大家通过以上已经掌握这套刀法基本使用了,那么上面曾说过,还可以对Adapter进行改造,从而节省开发过程中一些编码,那就一块瞅瞅呗~

刀法二部曲,巧用Adapter

创建一个item_layout作为接下来演示用~


  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.               android:layout_width="match_parent" 
  4.               android:layout_height="wrap_content" 
  5.               android:orientation="horizontal"> 
  6.  
  7.     <TextView 
  8.         android:id="@+id/item_username" 
  9.         android:layout_width="0dp" 
  10.         android:layout_height="wrap_content" 
  11.         android:layout_gravity="center_vertical" 
  12.         android:layout_weight="1"/> 
  13.  
  14.     <TextView 
  15.         android:id="@+id/item_userPwd" 
  16.         android:layout_width="0dp" 
  17.         android:layout_height="wrap_content" 
  18.         android:layout_gravity="center_vertical" 
  19.         android:layout_weight="1"/> 
  20.  
  21. </LinearLayout> 

很简单,没什么东西,接下来看adapter~


  1. package cn.hlq.butterknifestudy.adapter; 
  2.  
  3. import android.content.Context; 
  4. import android.view.LayoutInflater; 
  5. import android.view.View; 
  6. import android.view.ViewGroup; 
  7. import android.widget.BaseAdapter; 
  8. import android.widget.TextView; 
  9.  
  10. import java.util.ArrayList; 
  11. import java.util.List; 
  12.  
  13. import butterknife.BindView; 
  14. import butterknife.ButterKnife; 
  15. import cn.hlq.butterknifestudy.R; 
  16. import cn.hlq.butterknifestudy.model.Student; 
  17.  
  18. /** 
  19.  * Created by HLQ on 2017/4/11 0011. 
  20.  */ 
  21.  
  22. public class ListViewAdapter extends BaseAdapter { 
  23.  
  24.     private Context context; 
  25.     private List<Student> stuList = new ArrayList<Student>(); 
  26.  
  27.     public ListViewAdapter(Context context, List<Student> stuList) { 
  28.         this.context = context; 
  29.         this.stuList = stuList; 
  30.     } 
  31.  
  32.     @Override 
  33.     public int getCount() { 
  34.         return stuList != null ? stuList.size() : 0; 
  35.     } 
  36.  
  37.     @Override 
  38.     public Object getItem(int position) { 
  39.         return stuList != null ? stuList.get(position) : null; 
  40.     } 
  41.  
  42.     @Override 
  43.     public long getItemId(int position) { 
  44.         return position; 
  45.     } 
  46.  
  47.     @Override 
  48.     public View getView(int position, View convertView, ViewGroup parent) { 
  49.         ViewHolder viewHolder = null; 
  50.         if (viewHolder == null) { 
  51.             convertView = LayoutInflater.from(context).inflate(R.layout.item_listview_show, null); 
  52.             viewHolder = new ViewHolder(convertView); 
  53.             convertView.setTag(viewHolder); 
  54.         } else { 
  55.             viewHolder = (ViewHolder) convertView.getTag(); 
  56.         } 
  57.         Student stu = stuList.get(position); 
  58.         viewHolder.itemUsername.setText(stu.getUserName()); 
  59.         viewHolder.itemUserPwd.setText(stu.getUserPwd()); 
  60.         return convertView; 
  61.     } 
  62.  
  63.     static class ViewHolder { 
  64.         @BindView(R.id.item_username) 
  65.         TextView itemUsername; 
  66.         @BindView(R.id.item_userPwd) 
  67.         TextView itemUserPwd; 
  68.  
  69.         ViewHolder(View view) { 
  70.             ButterKnife.bind(this, view); 
  71.         } 
  72.     } 

运行结果为:

在此告诉大家一个小秘密,你可以直接右键layout,在生成注解时,选择自动创建ViewHolder,如下图:

是不是相当方便?在此,顺便捎带脚的介绍下,如何使用这把刀玩玩资源内容呢?


  1. // 初始化指定默认值 
  2.     @BindString(R.string.app_test) 
  3.     String titleContent;  
  4.  
  5.     lvTitle.setText(titleContent); 

运行结果如下:

除以上,刀法中还包含对以下支持,大家有兴趣自己了解即可,没什么难度了

 

而且官方上也提供了一些基本的使用,如下:

刀法三部曲BaseActivity封装,进一步简化代码

通常我们会封装一个BaseActivity,里面写好常用内容,之后activity继承此BaseActivity。同样我们也可以在此进行初始化,避免我们多次初始化,看下面一波代码~


  1. package com.heliquan.butterknife.base; 
  2.  
  3. import android.app.Activity; 
  4. import android.content.Context; 
  5. import android.os.Bundle; 
  6. import android.support.annotation.LayoutRes; 
  7. import android.view.KeyEvent; 
  8. import android.view.View; 
  9. import android.view.ViewGroup; 
  10.  
  11. import butterknife.ButterKnife; 
  12. import butterknife.Unbinder; 
  13.  
  14. /** 
  15.  * created by heliquan at 2017年4月14日 
  16.  */ 
  17. public abstract class BaseActivity extends Activity { 
  18.  
  19.     private Unbinder unbinder; 
  20.  
  21.     @Override 
  22.     protected void onCreate(Bundle savedInstanceState) { 
  23.         super.onCreate(savedInstanceState); 
  24.         // 必须重写setContentView()的三个方法,不然会出现子类继承无效,具体原因没有深入了解 
  25.         setContentView(getContentViewId()); 
  26.         unbinder = ButterKnife.bind(this); 
  27.     } 
  28.  
  29.     @Override 
  30.     public void setContentView(@LayoutRes int layoutResID) { 
  31.         super.setContentView(layoutResID); 
  32.         unbinder = ButterKnife.bind(this); 
  33.     } 
  34.  
  35.     @Override 
  36.     public void setContentView(View view) { 
  37.         super.setContentView(view); 
  38.         unbinder = ButterKnife.bind(this); 
  39.     } 
  40.  
  41.     @Override 
  42.     public void setContentView(View view, ViewGroup.LayoutParams params) { 
  43.         super.setContentView(view, params); 
  44.         unbinder = ButterKnife.bind(this); 
  45.     } 
  46.  
  47.     /** 
  48.      * 获取内容id 
  49.      */ 
  50.     protected abstract int getContentViewId(); 
  51.  
  52.     /** 
  53.      * 初始化View 
  54.      */ 
  55.     protected abstract void initView(); 
  56.  
  57.     @Override 
  58.     protected void onDestroy() { 
  59.         super.onDestroy(); 
  60.         unbinder.unbind(); 
  61.     } 
  62.  
  63.     /** 
  64.      * 根据id返回资源内容 
  65.      * 
  66.      * @param context 
  67.      * @param strId 
  68.      * @return 
  69.      */ 
  70.     protected String getStrResource(Activity activity, int strId) { 
  71.         return activity.getResources().getString(strId); 
  72.     } 
  73.  
  74.     /** 
  75.      * 监听返回按钮,点击返回finish当前页面 
  76.      * 
  77.      * @param keyCode 
  78.      * @param event 
  79.      * @return 
  80.      */ 
  81.     @Override 
  82.     public boolean onKeyDown(int keyCode, KeyEvent event) { 
  83.         if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { 
  84.             finish(); 
  85.             return true; 
  86.         } 
  87.         return super.onKeyDown(keyCode, event); 
  88.     } 

结束语

看到这里,想必大家已经基本对这套刀法有所了解以及能够基本运用了,感谢大家观看,如有不到之处,欢迎交流~

作者:静心Study

来源:51CTO

时间: 2024-10-06 14:42:42

一篇文章玩转ButterKnife,让代码更简洁的相关文章

提高可读性,3 个让代码更简洁的小技巧

在完成代码重构之后,我总是会获得一种莫名的成就感.其实,不仅是大规模的代码重构能给我带来这种感觉,一些小的修改也能让我感到很高兴.以下3个简单的重构技巧就能帮你改善代码的可读性. 1. 清理格式 代码的整体格式最能影响代码的可读性,让你迅速找到需要的代码.正确的缩进.分行和模式能帮助开发者省去大量的无用代码.你可以看看下面两种格式的比较.先看第一个格式: Inventory inventory = new Inventory(); for (int i = 0; i < cars.Count;

巧用函数-让你的代码更简洁

函数是指可以在应用中直接调用并实现特点"功能"的一段代码,在码栈中有系统函数和用户函数两种. 系统函数 系统函数也称为系统命令,用户可以直接使用,完整函数列表在后续会进行介绍. 用户函数 用户可通过使用 Func...EndFunc 语句来自定义函数.可按需要定义函数的参数及其返回值. 函数名必须用字母或下划线"_"开头, 剩下的部分(非首字符)则可在字母,数字或下划线中随意选择. 下面列出的都是合法的函数名:     MyFunc     Func1     _M

重构-使代码更简洁优美:实际经验之谈(提供一技巧,让你省掉N多代码)

这几天没怎么写文,因为在用 CYQ.Data  框架 重构以前的一个博客源码,而在重构的过程中,最关键的就是简化代码了.   今天,我将说一个很典型的示例,看完本示例后,不要惊讶,不要怀疑,它不是神马,也不是浮云,   而是很实在的一种方式,能让你节省了N多的代码,让你的代码看起来更简洁优美.   而这里说的一个很典型的示例,是从我目前重构中的博客中应用而来的:   一:正常的开发方式   1:扫一眼当前的项目解决方案   2:说说Module库 一般我们很常见的会有一个页面基类,当然各花叫法不

重构-使代码更简洁优美II:实际经验之谈(项目分层是怎么扯上代码节省的)

前言: 好几天没写文了,因为在折腾传说中的8国语言博客,实际目前预定义了10国+1自定义语言,代码还在慢慢的写着写着~~~~ 目前最新进展预览网址为:http://cyq.tupianshop.com/ ,其强大之处及 CYQ.Data 框架 V3.N 系列   后文再介绍了. 写文章有时候是需要有灵感或一时的冲动的~比如刚刚在改博客代码,经过一段思考,得到一些灵感,便有了此文.   在很久很久的 Long Long Ago 以前,写过一篇文章:重构-使代码更简洁优美:实际经验之谈(提供一技巧,

php 上一篇,下一篇文章实现代码与原理说明_php技巧

实现原理: 就是对id对进行order by id desc 或 order by id asc进行排序,然后再判断比当前id> or小于当前文章id的相同栏目的文章. 实例的sql语句如下: $id就是当面文章的id select * from news where id<$id order by id desc limit 0,1 select * from news where id>$id order by id desc limit 0,1 -- -- 表的结构 `string

php 上一篇与下一篇文章代码

基本知识: 就是对id对进行order by id desc 或  order by id asc进行排序,然后再判断比当前id> or小于当前文章id的 实例的sql语句如下: select * from news where id<$id order by id desc limit 0,1 select * from news where id>$id order by id desc limit 0,1 -- -- 表的结构 `string_find` -- CREATE TAB

一篇文章看懂Android学习最佳路线

前言 看到一篇文章中提到"最近几年国内的初级Android程序员已经很多了,但是中高级的Android技术人才仍然稀缺",这的确不假,从我在百度所进行的一些面试来看,找一个适合的高级Android工程师的确不容易,一般需要进行大量的面试才能挑选出一个比较满意的.为什么中高级Android程序员不多呢?这是一个问题,我不好回答,但是我想写一篇文章来描述下Android的学习路线,期望可以帮助更多的Android程序员提升自己.由于我也是从一个菜鸟过来的,所以我会结合我的个人经历以及我对A

一篇文章了解爬虫技术现状

本文讲的是一篇文章了解爬虫技术现状, 需求 万维网上有着无数的网页,包含着海量的信息,无孔不入.森罗万象.但很多时候,无论出于数据分析或产品需求,我们需要从某些网站,提取出我们感兴趣.有价值的内容,但是纵然是进化到21世纪的人类,依然只有两只手,一双眼,不可能去每一个网页去点去看,然后再复制粘贴.所以我们需要一种能自动获取网页内容并可以按照指定规则提取相应内容的程序,这就是爬虫. 原理 传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的

一篇文章读懂企业如何升级到云安全体系

本文讲的是一篇文章读懂企业如何升级到云安全体系,本文为青藤云安全供稿,青藤是国内首家自适应安全提供商,自适应安全是为数不多的云安全落地解决方案. 对于云安全这个新兴概念,从咨询机构.云平台到安全厂商,行业内各家机构众各有解读.但很少从企业角度出发,清楚指明安全部门对云安全这种全新解决方案的真实需求是如何产生的,以及如何规划云安全架构,如何和原有安全功能进行协同. 最近,Gartner的一篇分析报告提出了一种全新的安全解决方案--云工作负载安全平台(Cloud Workload Protectio