Android注解使用之ButterKnife 10注解使用介绍

ButterKnife介绍

App项目开发大部分时候还是以UI页面为主,这时我们需要调用大量的findViewById以及setOnClickListener等代码,控件的少的时候我们还能接受,控件多起来有时候就会有一种想砸键盘的冲动。所以这个时候我们想着可以借助注解的方式让我们从这种繁重的工作中脱离出来,也让代码变得更加简洁,便于维护,今天主要学习一下只专注View、Resource、Action注解框架ButterKnife。

ButterKnife是一个专注于Android系统的View、Resource、Action注入框架。

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ButterKnifeActivity extends AppCompatActivity {
private final static String TAG = ButterKnifeActivity.class.getSimpleName();
private Unbinder unbinder;
@BindString(R.string.butter_knife)
String butterKnifeStr;
@BindDrawable(R.mipmap.ic_launcher)
Drawable butterKnifeDrawable;
@BindView(R.id.btn_butter_knife)
Button butterKnifeBtn;
@BindView(R.id.iv_butter_knife)
ImageView butterKnifeIv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_butter_knife);
unbinder = ButterKnife.bind(this);
initViews();
}

private void initViews() {
butterKnifeBtn.setText(butterKnifeStr);
butterKnifeIv.setImageDrawable(butterKnifeDrawable);
}

@OnClick(R.id.btn_butter_knife)
public void onButterKnifeBtnClick(View view) {
Log.e(TAG, "onButterKnifeBtnClick");
}

@Override
protected void onDestroy() {
super.onDestroy();
unbinder.unbind();
}
}

ButterKnife优势

  • 强大的View绑定和Click事件处理功能,简化代码,提升开发效率
  • 方便的处理Adapter里的ViewHolder绑定问题
  • 运行时不会影响APP效率,使用配置方便
  • 代码清晰,可读性强

ButterKnife使用

在Project的build.gradle中添加配置

1
2
3
4
5
6
7
8
9
buildscript {
repositories {
mavenCentral()
google()
}
dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.0'
}
}

在Module的build.gradle添加配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'

android {
...
// Butterknife requires Java 8.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
implementation 'com.jakewharton:butterknife:10.2.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0'
}

注入和重置注入

Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ExampleActivity extends Activity {
private Unbinder unbinder;
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;

@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}

@Override protected void onDestroy() {
super.onDestroy();
unbinder.unbind();
}
}

Fragment

由于不同的视图生命周期,所以需要在onCreateView bind,在onDestroyView unbind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();
}
}

ViewHolder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MyAdapter extends BaseAdapter {
@Override public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view != null) {
holder = (ViewHolder) view.getTag();
} else {
view = inflater.inflate(R.layout.whatever, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
}

holder.name.setText("John Doe");
// etc...

return view;
}

static class ViewHolder {
@BindView(R.id.title) TextView name;
@BindView(R.id.job_title) TextView jobTitle;

public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}

view注入 @BindView,@BindViews

1
2
3
4
@BindView(R.id.btn_butter_knife)
Button butterKnifeBtn;
@BindViews({R.id.tv_butter_knife1, R.id.tv_butter_knife2, R.id.tv_butter_knife3})
List<TextView> textViews;

Resource注入

1
2
3
4
5
6
7
8
9
10
11
12
@BindString(R.string.title_btn_butter_knife)
String butterKnifeStr; //string注解使用
@BindDrawable(R.mipmap.ic_launcher)
Drawable butterKnifeDrawable; //Drawable注解使用
@BindBitmap(R.mipmap.ic_launcher)
Bitmap butterKnifeBitmap;; //Bitmap注解使用
@BindArray(R.array.day_of_week)
String weeks[]; //数组
@BindColor(R.color.colorPrimary)
int colorPrimary; //color注解使用
@BindDimen(R.dimen.activity_horizontal_margin)
Float spacer;

单事件注入

一个控件指定一个事件回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 不带参数
*/
@OnClick(R.id.btn_butter_knife)
public void onButterKnifeBtnClick() {
}

/**
* 带参数
*/
@OnClick(R.id.btn_butter_knife)
public void onButterKnifeBtnClick(View view) {
Log.e(TAG, "onButterKnifeBtnClick");
}

/**
* 带参数
* @param button
*/
@OnClick(R.id.btn_butter_knife)
public void onButterKnifeBtnClick(Button button) {
Log.e(TAG, "onButterKnifeBtnClick");
}

也可以多个控件指定一个事件回调

1
2
3
4
5
6
7
8
9
/**
* 两个不同的button都相应onButterKnifeBtnClick事件回调
*
* @param button
*/
@OnClick({R.id.btn_butter_knife, R.id.btn_butter_knife1})
public void onButterKnifeBtnClick(Button button) {
Log.e(TAG, "onButterKnifeBtnClick");
}

自定义的控件不通过ID也可以绑定到自己的事件

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

多事件回调

有一些View的listener是有多个回调方法的,比如EditText添加addTextChangedListener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override
public void afterTextChanged(Editable s) {

}
});

可以使用注解方式改成如下

1
2
3
4
5
6
7
8
9
10
11
12
@OnTextChanged(value = R.id.nameEditText, callback = OnTextChanged.Callback.BEFORE_TEXT_CHANGED)
void beforeTextChanged(CharSequence s, int start, int count, int after) {

}
@OnTextChanged(value = R.id.nameEditText, callback = OnTextChanged.Callback.TEXT_CHANGED)
void onTextChanged(CharSequence s, int start, int before, int count) {

}
@OnTextChanged(value = R.id.nameEditText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterTextChanged(Editable s) {

}

选择性注入

默认情况下,Bind和listener的注入都是必须的,如果target view没有被发现,则会报错。为了抑制这种行为,可以用@Optional注解来标记field和方法,让注入变成选择性的,如果targetView存在,则注入,不存在,则什么事情都不做。或者使用Android's "support-annotations" library中的@Nullable来修饰

1
2
3
4
5
6
7
@Nullable @BindView(R.id.might_not_be_there)
TextView mightNotBeThere;

@Optional @OnClick(R.id.maybe_missing)
void onMaybeMissingClicked() {
// TODO ...
}

ButterKnife.apply()函数

可以通过ButterKnife.apply()函数对view集合元素或者单个view的Action、Setter和Property进行修改

注:10.0及以上版本已废弃

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);

static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(value);
}
};

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

ButterKnife.findById()

ButterKnife 也提供了findById函数,通过findById()可以获取Activity、Dialog、View中的view,并且是泛型类型不需要强转

注:10.0及以上版本已废弃

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

ButterKnife自动生成插件安装:

Android Studio -> File -> Settings -> Plugins -> 搜索Zelezny下载添加即可,可以快速生成对应组件的实例对象,不用手动写。使用时,在要导入注解的Activity 或 Fragment 或 ViewHolder的layout资源代码上,右键 -> Generate -> Generate ButterKnife Injections

插件地址:https://github.com/avast/android-butterknife-zelezny

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :