最近在看GitHub上的一些代碼時凌箕,發(fā)現(xiàn)很多工程都用到了Butter Knife這個框架拧篮,能節(jié)省很多代碼量。像findViewById
這種代碼就不用再出現(xiàn)了牵舱,而且這個框架也提供了很多其他有用的注解他托。
抱著學(xué)習(xí)的心態(tài)看了官網(wǎng)上的文檔,挺簡單仆葡,也很實用赏参,決定以后就用這個庫了。
下面是我翻譯的官方文檔沿盅,諸位看官輕噴把篓。官方文檔也挺簡單,英語好的不好的腰涧,都建議去看看原文韧掩。
另外注意,這個庫的版本更新挺快的窖铡,我第一次用到的時候是7.1.0疗锐,而現(xiàn)在的最新版本已經(jīng)是8.5.1了坊谁,也就是說大家可能需要去ButterKnife的Github查看最近的版本。
Butter Knife
本文章翻譯自:http://jakewharton.github.io/butterknife/
Butter Knife滑臊,專門為Android View設(shè)計的綁定注解口芍,專業(yè)解決各種findViewById
。
簡介
對一個成員變量使用@BindView
注解雇卷,并傳入一個View ID鬓椭, ButterKnife 就能夠幫你找到對應(yīng)的View,并自動的進(jìn)行轉(zhuǎn)換(將View轉(zhuǎn)換為特定的子類):
class ExampleActivity extends Activity {
@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...
}
}
與緩慢的反射相比关划,Butter Knife使用再編譯時生成的代碼來執(zhí)行View的查找小染,因此不必?fù)?dān)心注解的性能問題。調(diào)用bind
來生成這些代碼贮折,你可以查看或調(diào)試這些代碼裤翩。
例如上面的例子,生成的代碼大致如下所示:
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);
}
資源綁定
綁定資源到類成員上可以使用@BindBool
调榄、@BindColor
踊赠、@BindDimen
、@BindDrawable
振峻、@BindInt
臼疫、@BindString
。使用時對應(yīng)的注解需要傳入對應(yīng)的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
// ...
}
在非Activity中使用綁定
Butter Knife提供了bind的幾個重載,只要傳入跟布局凤价,便可以在任何對象中使用注解綁定鸽斟。
例如在Fragment中:
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;
}
}
還有一種比較常見的場景,就是在ListView的Adapter中利诺,我們常常會使用ViewHolder:
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);
}
}
}
你能在提供給的例子中找到上述實現(xiàn)富蓄。
ButterKnife.bind
的調(diào)用可以被放在任何你想調(diào)用findViewById
的地方。
提供的其他綁定API:
使用Activity作為跟布局在任意對象中進(jìn)行綁定慢逾。如果你使用了類似MVC的編程模式立倍,你可以對controller使用它的Activity用
ButterKnife.bind(this, activity)
進(jìn)行綁定。使用
ButterKnife.bind(this)
綁定一個布局的子布局侣滩。如果你在布局中使用了<merge>
標(biāo)簽并且在自定義的控件構(gòu)造時inflate這個布局口注,你可以在inflate之后立即調(diào)用它【椋或者寝志,你可以在onFinishInflate()
回調(diào)中使用它。
View 列表
你可以一次性將多個views綁定到一個List
或數(shù)組中:
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
apply
函數(shù),該函數(shù)一次性在列表中的所有View上執(zhí)行一個動作:
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);
}
};
Android中的Property
屬性也可以使用apply
方法進(jìn)行設(shè)置:
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
監(jiān)聽器綁定
使用本框架材部,監(jiān)聽器能夠自動的綁定到特定的執(zhí)行方法上:
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
而監(jiān)聽器方法的參數(shù)都時可選的:
@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時,綁定事件監(jiān)聽不需要指定ID
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}
重置綁定:
Fragment的生命周期與Activity不同兽叮。在Fragment中芬骄,如果你在onCreateView
中使用綁定猾愿,那么你需要在onDestroyView
中設(shè)置所有view為null
鹦聪。為此,ButterKnife返回一個Unbinder
實例以便于你進(jìn)行這項處理蒂秘。在合適的生命周期回調(diào)中調(diào)用unbind
函數(shù)就可完成重置泽本。
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();
}
}
可選綁定:
在默認(rèn)情況下, @bind
和監(jiān)聽器的綁定都是必須的姻僧,如果目標(biāo)view沒有找到的話规丽,Butter Knife將會拋出個異常。
如果你并不想使用這樣的默認(rèn)行為而是想創(chuàng)建一個可選的綁定撇贺,那么你只需要在變量上使用@Nullable
注解或在函數(shù)上使用@Option
注解赌莺。
注意:任何名為@Nullable
的注解都可以使用在變量上。但還時強(qiáng)烈建議使用Android注解庫中的@Nullable
松嘶。使用這個庫對你的代碼有很多好處艘狭,關(guān)于該庫的詳情,可以點擊此處:Android Tools Project
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
對于包含多個方法的監(jiān)聽
當(dāng)一個監(jiān)聽器包含多個回調(diào)函數(shù)時翠订,使用函數(shù)的注解能夠?qū)ζ渲腥魏我粋€函數(shù)進(jìn)行綁定巢音。每一個注解都會綁定到一個默認(rèn)的回調(diào)。你也可以使用callback
參數(shù)來指定一個其他函數(shù)作為回調(diào)尽超。
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
福利
Butter Knife提供了一個findViewById
的簡化代碼:findById
官撼,用這個方法可以在View
、Activity
和Dialog
中找到想要View似谁,而且傲绣,該方法使用的泛型來對返回值進(jìn)行轉(zhuǎn)換,也就是說巩踏,你可以省去findViewById
前面的強(qiáng)制轉(zhuǎn)換了秃诵。
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);
如果你只是使用這個方法,可以使用靜態(tài)引入ButterKnife.findById
方法蛀缝。
下載
dependencies {
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
}
License
Copyright 2013 Jake Wharton
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.