Android Butter Knife使用詳解
1. 簡介
Butter Knife是一種View註解框架,可以大量減少模板類程式碼的書寫,極大簡化了類似findViewById 和OnClickedListener等View相關的程式碼。Butter Knife使用的java annotation Process技術實現,即在程式碼編譯階段就已經解析了註解內容並生成了模板程式碼,不會影響程式碼執行階段的效能。
Butter Knife最新版本為8.x, 官方程式碼託管在gitHub上,程式碼地址如下:
https://github.com/JakeWharton/butterknife
該庫的License是Apache License 2.0
2. 使用場景程式碼示例
對一個成員變數使用@BindView註解,並傳入一個View ID, ButterKnife 就能夠幫你找到對應的View, 並自動的進行轉換, 與緩慢的反射相比,Butter Knife 使用再編譯時生成的程式碼來執行View的查詢, 因此不必擔心註解的效能問題。呼叫bind來生成這些程式碼,你可以檢視或除錯這些程式碼。
要使用Butter Knife首先需要在 app Module下的build.gradle下引入相關的依賴庫
# 註解庫
implementation 'com.jakewharton:butterknife:8.8.1'
#編譯庫
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
2.1 Activity下使用Butter Knife
class ExampleActivity extends Activity {
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;
//繫結多個View
@BindViews({R.id.link_enterprise_text, R.id.link_enterprise_table,R.id.enterprise_sign,
R.id.enterprise_manager})
List<TextView> enterpriseInfoList;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
2.2 資源類繫結
繫結資源到類成員上可以使用@BindBool、@BindColor、@BindDimen、@BindDrawable、@BindInt、@BindString。使用時對應的註解需要傳入對應的id資源,例如@BindString你需要傳入R.string.id_string的字串的資源id。
class ExampleActivity extends Activity {
@BindString(R.string.title) String title;
@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red; // int or ColorStateList field
@BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field
// ...
}
2.3 非Activity場景——Fragment中繫結
Butter Knife提供了bind的幾個過載,只要傳入跟佈局,便可以在任何物件中使用註解繫結。
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
}
2.4 非Activity場景——Adapter中繫結
在ListView的Adapter中,我們常常會使用ViewHolder, 在該類下需要繫結相關View
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);
}
}
}
ButterKnife.bind的呼叫可以被放在任何你想呼叫findViewById的地方。
提供的其他繫結API:
使用Activity作為跟佈局在任意物件中進行繫結。如果你使用了類似MVC的程式設計模式,你可以對controller使用它的Activity用ButterKnife.bind(this, activity)進行繫結。
使用ButterKnife.bind(this)繫結一個佈局的子佈局。如果你在佈局中使用了標籤並且在自定義的控制元件構造時inflate這個佈局,你可以在inflate之後立即呼叫它。或者,你可以在onFinishInflate()回撥中使用它。
2.5 其他特性
1. 繫結View列表
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
2. 對View應用動作
apply函式,該函式一次性在列表中的所有View上執行一個動作:
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
Action和Setter介面能夠讓你指定一些簡單的動作:
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);
}
};
3. 對View應用屬性
Android中的Property屬性也可以使用apply方法進行設定:
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
2.6 監聽器繫結
使用本框架,監聽器能夠自動的繫結到特定的執行方法上:
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
而監聽器方法的引數都時可選的:
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}
指定一個特定的型別,Butter Knife也能識別:
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
可以指定多個View ID到一個方法上,這樣,這個方法就成為了這些View的共同事件處理。
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}
自定義View時,繫結事件監聽不需要指定ID
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}
2.7 重置繫結
Fragment的生命週期與Activity不同。在Fragment中,如果你在onCreateView中使用繫結,那麼你需要在onDestroyView中設定所有view為null。為此,ButterKnife返回一個Unbinder例項以便於你進行這項處理。在合適的生命週期回撥中呼叫unbind函式就可完成重置。
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();
}
}
2.8 可選繫結
可選繫結:
在預設情況下, @bind和監聽器的繫結都是必須的,如果目標view沒有找到的話,Butter Knife將會丟擲個異常。
如果你並不想使用這樣的預設行為而是想建立一個可選的繫結,那麼你只需要在變數上使用@Nullable註解或在函式上使用@Option註解。
注意:任何名為@Nullable的註解都可以使用在變數上。但還時強烈建議使用Android註解庫中的@Nullable。
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
2.9 對包含多個監聽方法的繫結——ListView OnItemSelectedListener
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
2.10 Butter Knife簡單findById方法
Butter Knife提供了一個findViewById的簡化程式碼:findById,用這個方法可以在View、Activity和Dialog中找到想要View,而且,該方法使用的泛型來對返回值進行轉換,也就是說,你可以省去findViewById前面的強制轉換了。
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);
3. Android Studio的外掛——Android ButterKnife Zelezny
配合ButterKnife實現註解,從此不用寫findViewById,想著就爽啊。在Activity,Fragment,Adapter中選中佈局xml的資源id自動生成butterknife註解。
使用方法:Ctrl+Shift+B選擇圖上所示選項.