ButterKnife的使用详解
16lz
2021-01-26
今天来讲解一下注解框架ButterKnife,此框架由Android之神Jake Wharton开源的。
GitHub的链接地址:https://github.com/JakeWharton/butterknife
ButterKnife框架的优点:
- 强大的View绑定和Click事件处理功能,简化代码,提升开发效率
- 方便的处理Adaper里的ViewHolder绑定问题
- 运行时不会影响app效率,使用配置方便
- 代码清晰,可读性强
一、在项目中导入ButterKnife
1、找到项目的app下的build.grade,直接添加下面两行依赖,刷新即可
dependencies { compile 'com.jakewharton:butterknife:8.5.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'}
2、在项目的build.gradle中添加
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.jakewharton:butterknife-gradle-plugin:8.5.1' }}
3、在主程序依赖Module的build.gradle中添加
apply plugin: 'com.android.library'apply plugin: 'com.jakewharton.butterknife'
注意:在依赖Module中使用,声明注解时用R2替代R, 例如:
class MainActivity extends Activity { @BindView(R2.id.user) EditText username; @BindView(R2.id.pass) EditText password; ...}
二、绑定ButterKnife
1.在Activity中绑定
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //绑定ButterKnife ButterKnife.bind(this); }}
2.在Fragment中绑定
注意:Fragment的生命周期不同于activity,在onCreateView中绑定一个Fragment时,在onDestroyView中将视图设置为null。当你调用bind来为你绑定一个Fragment时,Butter Knife会返回一个Unbinder的实例。在适当的生命周期(onDestroyView)回调中调用它的unbind方法进行Fragment解绑。
public class FirstFragment extends Fragment { private Unbinder unbinder; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_first, null); //绑定 unbinder = ButterKnife.bind(this, view); return view; } @Override public void onDestroyView() { super.onDestroyView(); //解绑 unbinder.unbind(); }}
3.在ViewHolder中绑定
static class ViewHolder { @BindView(R.id.btnOne) TextView btnOne; @BindView(R.id.imgOne) TextView imgOne; public ViewHolder(View view) { ButterKnife.bind(this, view); } }
三、绑定注解
名称 | 解析 |
---|---|
@BindView | 绑定一个view id为一个view 变量 |
@BindViews | 绑定多个view id为一个view的list变量 |
@BindArray | 绑定string里面array数组,@BindArray(R.array.city ) String[] citys ; |
@BindBitmap | 绑定图片资源为Bitmap,@BindBitmap( R.mipmap.wifi ) Bitmap bitmap; |
@BindBool | 绑定真假boolean |
@BindColor | 绑定color,@BindColor(R.color.colorAccent) int black; |
@BindDimen | 绑定Dimen,@BindDimen(R.dimen.borth_width) int mBorderWidth; |
@BindDrawable | 绑定Drawable,@BindDrawable(R.drawable.test_pic) Drawable mTestPic; |
@BindFloat | 绑定float |
@BindInt | 绑定int |
@BindString | 绑定一个String id为一个String变量,@BindString( R.string.app_name ) String meg; |
1. @BindView 绑定一个View
@BindView(R.id.btnOne) public Button btnOne; @BindView(R.id.imgOne) public ImageView imgOne;
2. @BindViews 绑定多个View
public class MainActivity extends AppCompatActivity { @BindViews({R.id.btnOne,R.id.btnTwo,R.id.btnThree}) public List
3. @BindArray 绑定绑定string里面array数组
先在String文件中添加一个array数组
<resources> <string name="app_name">ButterKnifeDemostring> <string-array name="language"> <item>Javaitem> <item>Kotlinitem> <item>Citem> <item>C++item> <item>PHPitem> <item>JavaScriptitem> string-array>resources>
而后直接绑定使用
public class MainActivity extends AppCompatActivity { @BindArray(R.array.language) String[] language; @BindViews({R.id.btnOne,R.id.btnTwo,R.id.btnThree}) public List
4. @BindBitmap 绑定资源图片
public class MainActivity extends AppCompatActivity { @BindView(R.id.imgOne) public ImageView imgOne; @BindBitmap(R.drawable.ic_launcher) public Bitmap ic_launcher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //绑定ButterKnife ButterKnife.bind(this); imgOne.setImageBitmap(ic_launcher); }}
5. @BindBool 绑定真假boolean
新建一个资源文件bool.xml
<?xml version="1.0" encoding="utf-8"?><resources> <bool name="isPlay">truebool> <bool name="isDo">falsebool>resources>
使用情况
@BindBool(R.bool.isPlay) public boolean isPlay;
6. @BindColor 绑定color
@BindColor(R.color.colorAccent) int colorAccent;
7. @BindDimen 绑定Dimen
先添加一个dimen.xml文件
<?xml version="1.0" encoding="utf-8"?><resources> <dimen name="textview_height">25dpdimen> <dimen name="textview_width">150dpdimen> <dimen name="ball_radius">3dpdimen> <dimen name="font_size">16spdimen>resources>
使用情况
@BindDimen(R.dimen.font_size) int font_size;
8. @BindDrawable 绑定Drawable
@BindDrawable(R.drawable.ic_launcher_background) Drawable ic_launcher_background;
9. @BindFloat 绑定Float
@BindFloat(R.dimen.font_size) float font_size;
10. @BindInt 绑定Int
先添加一个资源文件integer.xml
<?xml version="1.0" encoding="utf-8"?><resources> <integer name="max_value">99integer> <integer name="min_value">1integer>resources>
使用情况
@BindInt(R.integer.max_value) int max_value;
11. @BindString 绑定一个String
@BindString( R.string.app_name ) String appName;
四、事件注解
名称 | 作用 |
---|---|
@OnClick | 点击事件 |
@OnLongClick | 长按事件 |
@OnCheckedChanged | 选中,取消选中 |
@OnEditorAction | 软键盘的功能键 |
@OnFocusChange | 焦点改变 |
@OnItemClick | item被点击(注意这里有坑,如果item里面有Button等这些有点击的控件事件的,需要设置这些控件属性focusable为false) |
@OnItemLongClick | item长按(返回真可以拦截onItemClick) |
@OnItemSelected | item被选择事件 |
@OnPageChange | 页面改变事件 |
@OnTextChanged | EditText里面的文本变化事件 |
@OnTouch | 触摸事件 |
@Optional | 选择性注入,如果当前对象不存在,就会抛出一个异常,为了压制这个异常,可以在变量或者方法上加入一下注解,让注入变成选择性的,如果目标View存在,则注入, 不存在,则什么事情都不做=如下代码 |
1. @OnClick 绑定点击事件
@OnClick(R.id.btnOne) public void btnOne(View view) { } //无参 @OnClick(R.id.btnOne) public void btnOne() { } // 任意参数,默认强转,可为绑定View的子类 @OnClick(R.id.btnOne) public void buttonOnClick(Button btn) { btn.setText("按钮1"); } //绑定多个Id @OnClick({R.id.btnOne, R.id.btnTwo, R.id.btnThree}) public void buttonOnClick(View view) { switch (view.getId()) { case R.id.btnOne: Toast.makeText(this,"按钮1",Toast.LENGTH_SHORT).show(); break; case R.id.btnTwo: Toast.makeText(this,"按钮2",Toast.LENGTH_SHORT).show(); break; case R.id.btnThree: Toast.makeText(this,"按钮3",Toast.LENGTH_SHORT).show(); break; } } // 自定义 View,绑定自己的监听,不指定 ID public class MyButton extends Button { @OnClick public void onClick() { } }
2. @OnLongClick 绑定长按事件
@OnLongClick(R.id.btnOne) public boolean onLongClick(View view) { return true; }
3. @OnCheckedChanged 绑定选中,取消选中
演示布局样式
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context="com.itman.butterknifedemo.MainActivity"> <RadioGroup android:id="@+id/rg_main" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@color/white" android:orientation="vertical"> <RadioButton android:id="@+id/rbJava" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="false" android:text="Java" /> <RadioButton android:id="@+id/rbKotlin" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="false" android:text="Kotlin" /> <RadioButton android:id="@+id/rbJavaScript" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="false" android:text="JavaScript" /> RadioGroup>LinearLayout>
使用情况:
@OnCheckedChanged({R.id.rbJava,R.id.rbKotlin,R.id.rbJavaScript}) public void OnCheckedChangeListener(CompoundButton view, boolean ischanged ){ switch (view.getId()) { case R.id.rbJava: if (ischanged){//注意:这里一定要有这个判断,只有对应该id的按钮被点击了,ischanged状态发生改变,才会执行下面的内容 //选中,未选中变化状态的逻辑 } break; case R.id.rbKotlin: if (ischanged) { //选中,未选中变化状态的逻辑 } break; case R.id.rbJavaScript: if (ischanged) { //选中,未选中变化状态的逻辑 } break; default: break; } }
4. @OnEditorAction 绑定软件盘的功能键
@OnEditorAction(R.id.tvOne) public boolean onEditorAction(TextView view, int actionId, KeyEvent event) { return true; }
5. @OnFocusChange 绑定焦点改变
@OnFocusChange(R.id.etOne) public void onFocusChanged(View view, boolean hasFocus) { }
6. @OnItemClick 绑定Item的点击事件
@OnItemClick(R.id.lvContent) public void onItemClick(AdapterView<?> parent, View view, int position, long id) { }
7. @OnItemLongClick 绑定Item的长按事件
@OnItemLongClick(R.id.lvContent) public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { return true; }
8. @OnItemSelected 绑定Item被选择
//利用注解对Spinner item 作选择监听事件处理方式 @OnItemSelected(R.id.spContent)//默认callback为ITEM_SELECTED public void onItemSelected(int position) { Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show(); } /* * 注解onNothingSelected,需要在注解参数添加一个callback, * 注意的是Spinner中只要有数据,默认都会选中第0个数据,所以想进入到onNothingSelected()方法,就需要把Adapter中的数据都清空 */ @OnItemSelected(value = R.id.spContent, callback = OnItemSelected.Callback.NOTHING_SELECTED) public void onNothingSelected() { Toast.makeText(this, "Nothing", Toast.LENGTH_SHORT).show(); }
9. @OnPageChange 绑定页面改变事件
@OnPageChange(R.id.vpContent) public void onPageSelected(int position) { } @OnPageChange(value = R.id.vpContent, callback = PAGE_SCROLL_STATE_CHANGED) public void onPageStateChanged(int state) { } @OnPageChange(value = R.id.vpContent, callback = PAGE_SCROLLED) public void onPageStateChanged(int position, float positionOffset, int positionOffsetPixels) { }
10. @OnTextChanged 绑定EditText里面文本变化事件
@OnTextChanged(R.id.etContent) public void onTextChanged(CharSequence s, int start, int before, int count) { } @OnTextChanged(value = R.id.etContent, callback = BEFORE_TEXT_CHANGED) public void onBeforeTextChanged(CharSequence s, int start, int count, int after) { } @OnTextChanged(value = R.id.etContent, callback = AFTER_TEXT_CHANGED) public void onAfterTextChanged(Editable s) { }
11. @OnTouch 绑定触摸事件
@OnTouch(R.id.btnOne) public boolean onTouch(View view, MotionEvent event) { return false; }
12. @Optional 绑定选择性注入事件
@Optional @OnClick(R.id.maybe_missing) public void onMaybeMissingClicked() { }
五、代码混淆
-keep class butterknife.** { *; }-dontwarn butterknife.internal.**-keep class **$$ViewBinder { *; }-keepclasseswithmembernames class * { @butterknife.* ;}-keepclasseswithmembernames class * { @butterknife.* ;}
更多相关文章
- Android在onTouchEvent或setOnTouchListener中处理长按事件
- 探秘ListView的ConvertView以及ViewHolder原理
- 更新ADT20后出现This template depends on Android(安卓)Support
- 【android】使用Event Bus模式解耦Android(安卓)App组件间通信
- Android(安卓)开发艺术探究V第三章之view的事件分发机制
- 菜鸟进阶之Android(安卓)Touch事件传递(一)
- android手机震动的节奏例子--Vibrator对象及周期运用
- 第三部分:Android(安卓)应用程序接口指南---第二节:UI---第十章 拖
- 安卓TV开发(九) Android模拟事件 遥控器变身成鼠标来操作TV