当前位置:   article > 正文

Butterknife bindview @OnClick绑定多控件id_butterknife.onclick

butterknife.onclick


        

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

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

     那么,接下来为大家带来一个神器,助我们开发高效,快捷,下面是依赖包:

  1. compile 'com.jakewharton:butterknife:8.5.1'
  2. annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'

    首先还是先上代码吧:

  1. public class OwnerServiceActivity extends AppCompatActivity {
  2. @BindView(R.id.lin_city)//城市
  3. LinearLayout lin_city;
  4. @BindView(R.id.tx_limitline)//是否限行
  5. TextView tx_limitline;
  6. @BindView(R.id.tx_weather)//天气
  7. TextView tx_weather;
  8. @BindView(R.id.im_weather)//天气
  9. ImageView im_weather;
  10. @BindView(R.id.bt_stroll)
  11. Button bt_stroll;//去逛逛
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_owner_service);
  16. // lin_city.setOnClickListener(this);
  17. // initData();
  18. // lin_city = findViewById(R.id.lin_city);
  19. ButterKnife.bind(OwnerServiceActivity.this);
  20. }
  21. //监听事件
  22. @OnClick({R.id.tx_limitline,R.id.bt_stroll})//多个控件可以一起发在里面进行监听
  23. public void sayHi(View view) {
  24. switch (view.getId()) {
  25. case R.id.tx_limitline:
  26. Toast.makeText(this, "你按到我了啦1!", Toast.LENGTH_SHORT).show();
  27. break;
  28. case R.id.bt_stroll:
  29. Toast.makeText(this, "bt", Toast.LENGTH_SHORT).show();
  30. break;
  31. default:
  32. break;
  33. }
  34. }
  35. }

     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()绑定,如下:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); 必须在setContentView()之后绑定 ButterKnife.bind(this); }

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

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(); }}

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

2.单击事件

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

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

// 写法1 @OnClick(控件ID) void 方法名() { //业务逻辑操作 } // 写法2 @OnClick(控件ID) void 方法名(控件类型) { //业务逻辑操作 } // 写法3 @OnClick(控件ID) void 方法名(View view) { //业务逻辑操作 }

3.长按事件

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

// 方法1 boolean 方法名(){ // 业务逻辑操作 return false; } // 方法2 boolean 方法名(控件类型){ // 业务逻辑操作 return false; } // 方法3 boolean 方法名(View view){ // 业务逻辑操作 return false; }

4.Checked改变事件

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

// 写法1 @OnCheckedChanged(控件ID) void radioButtonCheckChange(boolean isl) { // 业务逻辑 } // 写法2 @OnCheckedChanged(控件ID) void radioButtonCheckChange(控件类型,boolean isl) { // 业务逻辑 }

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

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

// 写法1 @OnEditorAction(控件ID) boolean 方法名() { // 业务逻辑操作 return false; } // 写法2 // code:状态码 @OnEditorAction(控件ID) boolean EditTextAction(int code) { // 业务逻辑操作 return false; } // 写法3 // KeyEvent @OnEditorAction(控件ID) boolean EditTextAction(KeyEvent keyEvent) { // 业务逻辑操作 return false; } // 写法4 @OnEditorAction(控件ID) boolean EditTextAction(int code, KeyEvent keyEvent) { // 业务逻辑操作 return false; } // 写法5 @OnEditorAction(控件ID) boolean EditTextAction(TextView textView,int code, KeyEvent keyEvent) { // 业务逻辑操作 return false; }

6. EditText内容改变监听事件

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

@Target(METHOD)@Retention(CLASS)@ListenerClass( targetType = "android.widget.TextView", setter = "addTextChangedListener", remover = "removeTextChangedListener", type = "android.text.TextWatcher", ---> 这里同样对之前的TextWatcher做了相关处理 ggg callbacks = OnTextChanged.Callback.class ---> 自定义枚举,通过枚举类型标识当前操作 666)public @interface OnTextChanged { /** View IDs to which the method will be bound. */ @IdRes int[] value() default { View.NO_ID }; ---> 需要传入ID /** Listener callback to which the method will be bound. */ Callback callback() default Callback.TEXT_CHANGED; ---> 未改变状态 /** {@link TextWatcher} callback methods. */ enum Callback { ---> 枚举中分为三种类似 未改变 改变前 改变后 /** {@link TextWatcher#onTextChanged(CharSequence, int, int, int)} */ @ListenerMethod( name = "onTextChanged", ---> 当前标识为 未改变 parameters = { "java.lang.CharSequence", ---> 用户输入字符 "int", ---> 改变前个数 "int", ---> 测试时,返回0,没整明白代表什么意思 "int" ---> 根据打印结果,猜测这个应该是每次增加内容个数 } ) TEXT_CHANGED, /** {@link TextWatcher#beforeTextChanged(CharSequence, int, int, int)} */ @ListenerMethod( name = "beforeTextChanged", ---> 当前标识为 改变前 parameters = { "java.lang.CharSequence", ---> 用户输入字符 "int", ---> 改变前个数 "int", "int" } ) BEFORE_TEXT_CHANGED, /** {@link TextWatcher#afterTextChanged(android.text.Editable)} */ @ListenerMethod( name = "afterTextChanged", ---> 当前标识为 改变后 parameters = "android.text.Editable" ---> 用户输入字符 ) AFTER_TEXT_CHANGED, ---> 我们关注的重点在此,每次只需要监听这个,去做相关处理即可 }

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

// 内容改变后监听 // Editable editable:用户输入字符 @OnTextChanged(value = 控件ID, callback = 监听类型,改变后取值为:OnTextChanged.Callback.AFTER_TEXT_CHANGED) void editTextChangeAfter(Editable editable) { // 业务逻辑 } // 内容改变前监听 @OnTextChanged(value = 控件ID, callback = 监听类型,改变前取值为:OnTextChanged.Callback.BEFORE_TEXT_CHANGED) void editTextChangeBefore(CharSequence s, int start) { // 业务逻辑 } // 内容未发生改变监听 @OnTextChanged(value = 控件ID, callback = 监听类型,取值为:OnTextChanged.Callback.TEXT_CHANGED) void editTextChange(CharSequence s, int start) { // 业务逻辑 }

7. 焦点监听事件

由此可见,如下:

@OnFocusChange(控件ID) void editTextFocus(boolean isl){ // 业务逻辑 }

8. 触摸监听事件

写法如下:

@OnTouch(控件ID) boolean imageView(MotionEvent event){ // 业务逻辑 return false; }

9. item项单击监听事件

@OnItemClick(控件ID) void listItemClick(int position){ // 业务逻辑 }

10. item项长按监听事件

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

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为例)

代码如下:

@OnClick(R.id.text) void textClick() { Toast.makeText(MainActivity.this, "TextView的单击事件触发。。。(无参-默认)", Toast.LENGTH_SHORT).show(); } @OnClick(R.id.text) void textClick(TextView textView){ Toast.makeText(MainActivity.this, "TextView的单击事件触发。。。(TextView)", Toast.LENGTH_SHORT).show(); } @OnClick(R.id.text) void textClick(View view){ Toast.makeText(MainActivity.this, "TextView的单击事件触发。。。(View)", Toast.LENGTH_SHORT).show(); }

运行结果展示:

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

代码如下:

@OnLongClick(R.id.button) boolean buttonLongClick(){ Toast.makeText(MainActivity.this, "Button的长按事件触发。。。(无参-默认)", Toast.LENGTH_SHORT).show(); return false; }// @OnLongClick(R.id.button)// boolean buttonLongClick(Button button){// Toast.makeText(MainActivity.this, "Button的长按事件触发。。。(TextView)", Toast.LENGTH_SHORT).show();// return false;// }// @OnLongClick(R.id.button)// boolean buttonLongClick(View view){// Toast.makeText(MainActivity.this, "Button的长按事件触发。。。(View)", Toast.LENGTH_SHORT).show();// return false;// }

运行结果如下:

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

Multiple listener methods with return value specified for ID:2131165193

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

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

代码如下:

@OnCheckedChanged(R.id.checkBox) void radioButtonCheckChange(boolean isl) { Toast.makeText(MainActivity.this, "CheckBox。。。(无参)" + isl, Toast.LENGTH_SHORT).show(); } @OnCheckedChanged(R.id.checkBox) void radioButtonCheckChange(CheckBox checkBox,boolean isl) { Toast.makeText(MainActivity.this, "CheckBox。。。(CheckBox)" + isl, Toast.LENGTH_SHORT).show(); }

运行结果如下:

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

代码如下:

// @OnEditorAction(R.id.tv_editor_action)// boolean EditTextAction() {// Toast.makeText(MainActivity.this, " 点击---通往天堂 无参", Toast.LENGTH_SHORT).show();// return false;// }// @OnEditorAction(R.id.tv_editor_action)// boolean EditTextAction(int code) {// Toast.makeText(MainActivity.this, " 点击---通往天堂 code:"+code, Toast.LENGTH_SHORT).show();// return false;// }// @OnEditorAction(R.id.tv_editor_action)// boolean EditTextAction(KeyEvent keyEvent) {// Toast.makeText(MainActivity.this, "点击---通往天堂 KeyEvent:"+keyEvent, Toast.LENGTH_SHORT).show();// return false;// }// @OnEditorAction(R.id.tv_editor_action)// boolean EditTextAction(int code, KeyEvent keyEvent) {// Toast.makeText(MainActivity.this, "点击---通往天堂 code:"+code+" KeyEvent:"+keyEvent, Toast.LENGTH_SHORT).show();// return false;// } @OnEditorAction(R.id.tv_editor_action) boolean EditTextAction(TextView textView,int code, KeyEvent keyEvent) { Toast.makeText(MainActivity.this, textView.getText().toString()+" 点击---通往天堂 code:"+code+" KeyEvent:"+keyEvent, Toast.LENGTH_SHORT).show(); return false; }

运行效果下:

5. EditText内容改变监听事件

代码如下:

@OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED) void editTextChangeAfter(Editable editable) { Toast.makeText(MainActivity.this, "改变后内容为:"+editable.toString(), Toast.LENGTH_SHORT).show(); System.out.println("改变后---内容为:"+editable.toString()); } @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.BEFORE_TEXT_CHANGED) void editTextChangeBefore(CharSequence s, int start, int before, int count) { Toast.makeText(MainActivity.this, "编辑内容为:"+s+",开始前个数:"+start, Toast.LENGTH_SHORT).show(); System.out.println("改变前---内容为:"+s+",开始前个数:"+start+",:"+before+","+count); } @OnTextChanged(value = R.id.editText, callback = OnTextChanged.Callback.TEXT_CHANGED) void editTextChange(CharSequence s, int start, int before, int count) { Toast.makeText(MainActivity.this, "编辑内容为:"+s+",开始前个数:"+start, Toast.LENGTH_SHORT).show(); System.out.println("未编辑---内容为:"+s+",开始前个数:"+start+","+before+","+count); }

6.焦点监听事件

代码如下:

@OnFocusChange(R.id.editTextFocus) void editTextFocus(boolean isl) { if (isl) { Toast.makeText(MainActivity.this, "获取焦点" + isl, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "失去焦点" + isl, Toast.LENGTH_SHORT).show(); } }

运行结果如下:

7. 触摸监听事件

代码如下:

@OnTouch(R.id.imageView) boolean imageView(MotionEvent event){ System.out.println(event); return false; }

运行结果如下:

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单击以及长按监听事件

代码如下:

@OnItemClick(R.id.listView) void listItemClick(int position){ Toast.makeText(this,"OnItemClick---点击了第"+position+"个",Toast.LENGTH_SHORT).show(); } @OnItemLongClick(R.id.listView) boolean listItemLongClick(int position) { Toast.makeText(this, "OnItemLongClick---点击了第" + position + "个", Toast.LENGTH_SHORT).show(); return true; }

运行结果如下:

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

刀法二部曲,巧用Adapter

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

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/item_username" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1"/> <TextView android:id="@+id/item_userPwd" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1"/></LinearLayout>

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

package cn.hlq.butterknifestudy.adapter;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import java.util.ArrayList;import java.util.List;import butterknife.BindView;import butterknife.ButterKnife;import cn.hlq.butterknifestudy.R;import cn.hlq.butterknifestudy.model.Student;/** * Created by HLQ on 2017/4/11 0011. */public class ListViewAdapter extends BaseAdapter { private Context context; private List<Student> stuList = new ArrayList<Student>(); public ListViewAdapter(Context context, List<Student> stuList) { this.context = context; this.stuList = stuList; } @Override public int getCount() { return stuList != null ? stuList.size() : 0; } @Override public Object getItem(int position) { return stuList != null ? stuList.get(position) : null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (viewHolder == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_listview_show, null); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } Student stu = stuList.get(position); viewHolder.itemUsername.setText(stu.getUserName()); viewHolder.itemUserPwd.setText(stu.getUserPwd()); return convertView; } static class ViewHolder { @BindView(R.id.item_username) TextView itemUsername; @BindView(R.id.item_userPwd) TextView itemUserPwd; ViewHolder(View view) { ButterKnife.bind(this, view); } }}
在此告诉大家一个小秘密,你可以直接右键layout,在生成注解时,选择自动创建ViewHolder

顺便捎带脚的介绍下,如何使用这把刀玩玩资源内容:// 初始化指定默认值 @BindString(R.string.app_test) String titleContent; lvTitle.setText(titleContent);

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

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

package com.heliquan.butterknife.base;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.support.annotation.LayoutRes;import android.view.KeyEvent;import android.view.View;import android.view.ViewGroup;import butterknife.ButterKnife;import butterknife.Unbinder;/** * created by heliquan at 2017年4月14日 */public abstract class BaseActivity extends Activity { private Unbinder unbinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 必须重写setContentView()的三个方法,不然会出现子类继承无效,具体原因没有深入了解 setContentView(getContentViewId()); unbinder = ButterKnife.bind(this); } @Override public void setContentView(@LayoutRes int layoutResID) { super.setContentView(layoutResID); unbinder = ButterKnife.bind(this); } @Override public void setContentView(View view) { super.setContentView(view); unbinder = ButterKnife.bind(this); } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { super.setContentView(view, params); unbinder = ButterKnife.bind(this); } /** * 获取内容id */ protected abstract int getContentViewId(); /** * 初始化View */ protected abstract void initView(); @Override protected void onDestroy() { super.onDestroy(); unbinder.unbind(); } /** * 根据id返回资源内容 * * @param context * @param strId * @return */ protected String getStrResource(Activity activity, int strId) { return activity.getResources().getString(strId); } /** * 监听返回按钮,点击返回finish当前页面 * * @param keyCode * @param event * @return */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { finish(); return true; } return super.onKeyDown(keyCode, event); }}




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/197865
推荐阅读
相关标签
  

闽ICP备14008679号