項(xiàng)目地址
GitHub地址:https://github.com/JakeWharton/butterknife
簡(jiǎn)介
ButterKnife這個(gè)開(kāi)源庫(kù)可以讓我們從大量的findViewById和setOnClickListener中解放出來(lái)革半,其對(duì)性能的影響微乎其微(其自定義注解的實(shí)現(xiàn)都是限定為RetentionPolicy.CLASS,也就是編譯出.class文件為止有效磷蛹,在運(yùn)行時(shí)不額外消耗性能,其實(shí)通過(guò)java注解自動(dòng)生成java代碼的形式來(lái)完成工作)苍蔬,但也有一個(gè)明顯的缺點(diǎn)游两,那就是代碼的可讀性差些,凡事有利有弊托慨,我們需要做到有的放矢葵孤。
應(yīng)用
Activity Binding
class ExampleActivity extends Activity {
@Bind(R.id.title) TextView title;
@Bind(R.id.subtitle) TextView subtitle;
@Bind(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...
}
}
調(diào)用注解bind生成的代碼是可見(jiàn)的并且能夠調(diào)試担钮,上面的示例通過(guò)Bind注解生成的代碼相當(dāng)于下面的代碼:
public void bind(ExampleActivity activity) {
activity.subtitle = (android.widget.TextView) activity.findViewById(2130968578);
activity.footer = (android.widget.TextView) activity.findViewById(2130968579);
activity.title = (android.widget.TextView) activity.findViewById(2130968577);
}
RESOURCE BINDING
Bind pre-defined resources with @BindBool, @BindColor, @BindDimen, @BindDrawable, @BindInt, @BindString, which binds an R.bool ID (or your specified type) to its corresponding field.
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
// ...
}
NON-ACTIVITY BINDING
public class FancyFragment extends Fragment {
@Bind(R.id.button1) Button button1;
@Bind(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;
}
}
ADAPTER BINDING
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 {
@Bind(R.id.title) TextView name;
@Bind(R.id.job_title) TextView jobTitle;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}
LIST OR ARRAY BINDING
@Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
//允許同時(shí)作用于list中的view
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
//Action and Setter interfaces allow specifying simple behavior.
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);
}
};
//An Android Property can also be used with the apply method.
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
LISTENER BINDING
//帶View參數(shù)
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
//不帶View參數(shù)
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}
//帶Button參數(shù)
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
//同時(shí)注入多個(gè)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();
}
}
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}
BINDING RESET
相對(duì)于Activity,F(xiàn)ragment有與之不同的視圖聲明周期尤仍。當(dāng)早onCreateView中bind一個(gè)Fragment的時(shí)候箫津,需要在OnDestroyView中將views設(shè)置為null。Butter Knife 通過(guò)一個(gè)ButterKnife.Unbinder接口來(lái)自動(dòng)完成這個(gè)過(guò)程. Simply bind an unbinder with @Unbinder to the fragment.
public class FancyFragment extends Fragment {
@Bind(R.id.button1) Button button1;
@Bind(R.id.button2) Button button2;
@Unbinder ButterKnife.Unbinder unbinder;
@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;
}
@Override public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}
OPTIONAL BINDINGS
默認(rèn)情況下,@Bind和綁定的目標(biāo)是必須存在的,如果目標(biāo)View不存在將會(huì)拋出異常苏遥。
為了避免這樣情況并且創(chuàng)建一個(gè)可選的綁定目標(biāo)送挑,給變量增加@Nullable注解或者給方法增加 @Optional注解.
Note: Any annotation named @Nullable or can be used for fields. It is encouraged to use the @Nullable annotation from Android's "support-annotations" library.
//給變量增加@Nullable注解
@Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere;
//給方法增加@Optional注解
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
MULTI-METHOD LISTENERS
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
BONUS
Also included are findById methods which simplify code that still has to find views on a View, Activity, or Dialog. It uses generics to infer the return type and automatically performs the cast.
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);