今天来讲解一下注解框架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<Button> btnList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定ButterKnife
ButterKnife.bind(this);
btnList.get(0).setText("按钮One");
btnList.get(1).setText("按钮Two");
btnList.get(2).setText("按钮Three");
}
}
3. @BindArray 绑定绑定string里面array数组
先在String文件中添加一个array数组
<resources>
<string name="app_name">ButterKnifeDemo</string>
<string-array name="language">
<item>Java</item>
<item>Kotlin</item>
<item>C</item>
<item>C++</item>
<item>PHP</item>
<item>JavaScript</item>
</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<Button> btnList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定ButterKnife
ButterKnife.bind(this);
btnList.get(0).setText(language[0]);
btnList.get(1).setText(language[1]);
btnList.get(2).setText(language[2]);
}
}
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">true</bool>
<bool name="isDo">false</bool>
</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">25dp</dimen>
<dimen name="textview_width">150dp</dimen>
<dimen name="ball_radius">3dp</dimen>
<dimen name="font_size">16sp</dimen>
</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">99</integer>
<integer name="min_value">1</integer>
</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.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}