【开源项目7】Android视图注入库:butterknife

it2022-05-08  6

介绍 ButterKnife通过@InjectView和视图的ID注解的变量去找到并自动转换为你布局上相应的布局视图。 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 Use "injected" views...   } } 与缓慢的反射机制不同的是,产生的代码是用来执行视图的查表(查找视图)操作。调用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); }非activity注入 你也可以提供自己的根视图对任意对象执行注入: 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 Use "injected" views...     return view;   } } 另外一个用法是,在列表适配器中简化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 {     @InjectView(R.id.title) TextView name;     @InjectView(R.id.job_title) TextView jobTitle;     public ViewHolder(View view) {       ButterKnife.inject(this, view);     }   } } 你可以在上面例子中查看其行为的实现。你可以在任意可以使用findViewById的地方使用ButterKnife.inject。 其他提供的注入API:     可以使用activity作为根视图对任意对象进行注入。如果你使用了类似MVC的架构,你可以通过在控制器(C)的activity使用ButterKnife.inject(this, activity)对其进行注入。     可以使用ButterKnife.inject(this)对子视图进行注入。如果你在布局中使用<merge>标签而且载入了自定义控件,可以在后面立即调用它。或者通过xml载入的自定义视图,可以在onFinishInflate()回调中使用它。视图列 你可以把多个视图集中到列表或者数组中。 @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);   } } Android的自带属性也可以用apply方法。 ButterKnife.apply(nameViews, View.ALPHA, 0); 点击监听注入 点击监听也可以自动设置到方法。 @OnClick(R.id.submit) public void submit() {   // TODO submit data to server... } 你可以把视图当做参数传入方法。声明一个指定类型 @OnClick(R.id.submit) public void sayHi(Button button) {   button.setText("Hello!"); } 在一个绑定中为相同的事件操作声明多个ID。 @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();   } }注入重置 fragment比起activity有更加不同的声明周期,当在fragment的onCreateView里注入时,应该在onDestroyView里设置视图为空。ButterKnife有一个重置方法可以自动做这个操作。 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 Use "injected" views...     return view;   }   @Override void onDestroyView() {     super.onDestroyView();     ButterKnife.reset(this);   } }可选注入 默认情况下,@InjectView和@OnClick是必须的(此处的必须应该是对应后面一句话而言的)。如果目标视图未找到会抛异常。为了禁止这种行为的出现并创建一个可选的注入,添加@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查找视图。它使用generics推断返回类型并自动执行转换。 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添加静态引入会更加有趣。介绍 ButterKnife通过@InjectView和视图的ID注解的变量去找到并自动转换为你布局上相应的布局视图。 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 Use "injected" views...   } } 与缓慢的反射机制不同的是,产生的代码是用来执行视图的查表(查找视图)操作。调用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); }非activity注入 你也可以提供自己的根视图对任意对象执行注入: 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 Use "injected" views...     return view;   } } 另外一个用法是,在列表适配器中简化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 {     @InjectView(R.id.title) TextView name;     @InjectView(R.id.job_title) TextView jobTitle;     public ViewHolder(View view) {       ButterKnife.inject(this, view);     }   } } 你可以在上面例子中查看其行为的实现。你可以在任意可以使用findViewById的地方使用ButterKnife.inject。 其他提供的注入API:     可以使用activity作为根视图对任意对象进行注入。如果你使用了类似MVC的架构,你可以通过在控制器(C)的activity使用ButterKnife.inject(this, activity)对其进行注入。     可以使用ButterKnife.inject(this)对子视图进行注入。如果你在布局中使用<merge>标签而且载入了自定义控件,可以在后面立即调用它。或者通过xml载入的自定义视图,可以在onFinishInflate()回调中使用它。视图列 你可以把多个视图集中到列表或者数组中。 @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);   } } Android的自带属性也可以用apply方法。 ButterKnife.apply(nameViews, View.ALPHA, 0); 点击监听注入 点击监听也可以自动设置到方法。 @OnClick(R.id.submit) public void submit() {   // TODO submit data to server... } 你可以把视图当做参数传入方法。声明一个指定类型 @OnClick(R.id.submit) public void sayHi(Button button) {   button.setText("Hello!"); } 在一个绑定中为相同的事件操作声明多个ID。 @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();   } }注入重置 fragment比起activity有更加不同的声明周期,当在fragment的onCreateView里注入时,应该在onDestroyView里设置视图为空。ButterKnife有一个重置方法可以自动做这个操作。 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 Use "injected" views...     return view;   }   @Override void onDestroyView() {     super.onDestroyView();     ButterKnife.reset(this);   } }可选注入 默认情况下,@InjectView和@OnClick是必须的(此处的必须应该是对应后面一句话而言的)。如果目标视图未找到会抛异常。为了禁止这种行为的出现并创建一个可选的注入,添加@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查找视图。它使用generics推断返回类型并自动执行转换。 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添加静态引入会更加有趣。

转载于:https://www.cnblogs.com/dongdong230/p/4183024.html


最新回复(0)