
使用 @InjectView 这种注释字段及一个视图的编号(ID)来让Butter Knife 找到布局中由妳指定的视图并且自动地将对应的视图转换成适当的类型。
class ExampleActivity extends Activity {
@InjectView(R.id.title) TextView title;
@InjectView(R.id.subtitle) TextView subtitle;
@InjectView(R.id.footer) TextView footer;
@Override public void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife .inject(this);
// TODO 使用 这些“已注入”的视图……
}
}
视图的查找不是通过慢得冒屎的反射来实现的,而是生成了实际的代码来实现的。调用 inject 就会触发这段生成的代码, 这段代码妳可以看到,还可以对它进行调试。
针对以上示例,所生成的代码大致是以下样子的:
public void inject(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);
}
妳还可以通过提供妳自己的视图根元素的方式来对任意的对象进行注入。
public class FancyFragment extends Fragment {
@InjectView(R.id.button1) Button button1;
@InjectView(R.id.button2) Button button2;
@Override View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife .inject(this, view);
// TODO 使用那些 “注入后”的视图……
return 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");
// 等等……
return convertView;
}
static class ViewHolder {
@InjectView(R.id.title) TextView name;
@InjectView(R.id.job_title) TextView jobTitle;
public ViewHolder ( View view) {
ButterKnife .inject(this, view);
}
}
}
妳可以在附带的示例中看到这种实现。
所提供的其它注入用的应用编程接口:
•. 使用 一个活动作为视图根元素,注入任意的对象。如果 妳使用一种类似于 MVC 的模式的话, 妳可以通过 ButterKnife.inject(this, activity) 来使用某个控制器的活动注入该控制器。
•. 使用 ButterKnife.inject(this) 来将某个视图的子代元素注入到字段中。如果 妳在某个布局中使用了 <merge> 标记,并且 在一个自定义的视图构造函数中填充( inflate )它的话,那么 ,妳可以在之后立即调用这个方法。或者 ,通过XML 填充得到 的自定义类型也可以在它的 onLayoutInflated() 回调函数中使用这个方法。
妳可以将多个视图组织到一个列表( List )或数组中。
@InjectViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
apply 方法 可用来一次性对一个列表中的所有视图做同一个操作。
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
动作 ( Action )和 设置器( Setter )使得妳能够指定简单的行为。
static final Action<View> DISABLE = new Action<>() {
@Override public void apply( View view, int index) {
view.setEnabled(false);
}
}
static final Setter<View, Boolean> ENABLED = new Setter<>() {
@Override public void set( View view, Boolean value, int index) {
view.setEnabled(value);
}
}
还可以使用 apply 方法来设置一个安卓属性( Property )的值。
ButterKnife.apply(nameViews, View.ALPHA, 0);
点击事件监听器也可以被自动配置到指定的方法上去。
@OnClick(R.id.submit)
public void submit() {
// TODO 将数据提交到服务器……
}
妳可以将视图作为一个参数添加到这个方法中。定义一个特定的类型,它会被自动进行类型转换。
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
在单个绑定中指定多个视图编号(IDs),以实现通用的事件处理。
@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();
}
}
片断 ( Fragments )的生命周期与活动的生命周期是不同的。如果 妳在 onCreateView 方法中对一个片断进行注入的话,要注意在 onDestroyView 方法中将各个视图设置为空( null )。 Butter Knife 有一个 reset 方法 ,可以自动完成这件事。
public class FancyFragment extends Fragment {
@InjectView(R.id.button1) Button button1;
@InjectView(R.id.button2) Button button2;
@Override View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife .inject(this, view);
// TODO 使用那些 “被注入”的视图……
return view;
}
@Override void onDestroyView() {
super.onDestroyView();
ButterKnife .reset(this);
}
}
默认情况 下, @InjectView 和 @OnClick 注入动作 都是要进行严格(required)查找的。如果 找不到目标视图的话,会抛出一个异常。
要想关闭这种行为,创建一个可选的注入的话,只需向该字段或方法中加入 @Optional 注释就可以了。
@Optional @InjectView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
那种 其对应的监听器拥有多个回调函数的方法注释, 可用来与其中的任何一个回调函数绑定。每个注释 都有一个与之绑定的默认回调函数。 可使用 callback 参数来指定一个替代回调函数。
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
项目 中还包含了两个 findById 方法,它们简化 了那些仍然需要在 一个 View 或 Activity 上寻找视图的代码。 它使用泛型来推断返回对象的类型,并且自动做类型转换。
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.findById 的一个静态引入, 妳将享受到更多的乐趣。
这个库、示例程序以及本网站,它们的源代码都 在 GitHub 上 。 还 可以浏览到 Javadoc 。
某些集成开发环境需要做一些额外的配置,才能够启用注释处理。
•. Eclipse — 手动配置 。
未知美人
HxLauncher: Launch Android applications by voice commands