简介


特点:
  • 采用注解的方式实现强大的View绑定和Click事件处理功能,简化代码,提升开发效率
  • 方便的处理Adapter里的ViewHolder绑定问题
  • 是一种依赖注入框架,运行时不会影响APP效率(原理和dagger一样,是在编译期生成代码,与反射没有半毛钱关系)
  • 使用配置方便 ,代码清晰,可读性强

Field and method binding for Android views which uses annotation processing to generate boilerplate code样板代码 for you.
  • Eliminate消除 findViewById calls by using @BindView on fields.
  • Group multiple views组合多个视图 in a list or array. Operate on all of them at once with actions, setters, or properties.
  • Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and others.
  • Eliminate resource lookups by using resource annotations on fields.

Remember: A butter knife is like a dagger only infinitely less sharp(无限锐利).


【如何将注解和字段放在一行】
效果如下:
设置方式:
settings-->editor-->code style-->java-->wrapping and braces-->Field annotation 


【如何使用插件自动生成代码】
使用Zelezny插件,可一键生成所有定义id的View的声明及onclick事件。
在AndroidStudio->File->Settings->Plugins->搜索【Zelezny】下载添加即可。
使用时,在要导入注解的Activity 或 Fragment 或 ViewHolder的【layout】资源代码上,右键 --> Generate --> Generate ButterKnife Injections 【alt+F1】

Gradle配置

新版本只需添加以下两行依赖即可
//旧版本需在gradle进行好几项配置,新版本只需添加以下两行依赖即可。新版本和旧版本API不一致,建议赶快升级!
compile 'com.jakewharton:butterknife:8.8.1'//2017-9-21最新版本
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'//编译器
1、在项目的build.gradle中添加:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'//每个Android项目默认都会带的
//PS:在新版本中千万不要加这些,日了狗了,加上去之后反而不会生成需要的文件,进而导致完全不能使用ButterKnife。
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'//这个是需要我们手动添加的,apt是用于自动生成代码来进行依赖注入的
}
android-apt是Gradle编译器的插件,根据其官方文档,主要两个目的:
  • 编译时使用该工具,最终打包时不会将该插件打入到apk中。
  • 能够根据设置的源路径,在编译时期生成相应代码。

2、在module的build.gradle中添加:

apply plugin: 'com.android.application'//每个Android项目默认都会带的。在build.gradle的第一行
//PS:在新版本中千万不要加这些,日了狗了,加上去之后反而不会生成需要的文件,进而导致完全不能使用ButterKnife。
apply plugin: 'com.neenbedankt.android-apt'//apt支持
3、在module的build.gradle中添加:
compile 'com.jakewharton:butterknife:8.8.1'//2017-9-21最新版本
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'//为编译时期生成代码等相关的类库
在android-apt的文档中,也推荐使用这种方式。因为,编译时期生成代码的类库在运行期并不需要,那么将其分为两个库:运行类库butterknife/dagger和 编译器生成代码类库butterknife-compiler/dagger-compiler。那么在打包时,就不需要将butterknife-compiler/dagger-compiler打入其中,减小APK 的大小。

Butter Knife中定义的注解

注解分为三种:以Bind开头的绑定资源的注解,以On开头的注册事件监听的注解,以Listener开头的辅助On**注解的内部注解。
   
BindView
//Bind a field to the view for the specified ID. The view will automatically be cast to the field type.
@Retention(CLASS)
@Target(FIELD)
public @interface BindView {
/** View ID to which the field will be bound. */
@IdRes int value();
}
 BindViews
// Bind a field to the view for the specified ID. The view will automatically be cast to the field type.
@Retention(CLASS) @Target(FIELD)
public @interface BindViews {
/** View IDs to which the field will be bound. */
@IdRes int[] value();
} @BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> nameViews;
BindString
//Bind a field to the specified string resource ID.
@Retention(CLASS) @Target(FIELD)
public @interface BindString {
/** String resource ID to which the field will be bound. */
@StringRes int value();
}
BindBitmap
//Bind a field to a Bitmap from the specified drawable resource ID.
@Retention(CLASS) @Target(FIELD)
public @interface BindBitmap {
/** Drawable resource ID from which the Bitmap will be created. */
@DrawableRes int value();
} @BindBitmap(R.drawable.logo) Bitmap logo;
BindDrawable
//Bind a field to the specified drawable resource ID.
@Retention(CLASS) @Target(FIELD)
public @interface BindDrawable {
/** Drawable resource ID to which the field will be bound. */
@DrawableRes int value(); /** Color attribute resource ID that is used to tint the drawable. */
@AttrRes int tint() default 0;
} @BindDrawable(R.drawable.placeholder) Drawable placeholder;
@BindDrawable(value = R.drawable.placeholder, tint = R.attr.colorAccent) Drawable tintedPlaceholder;
OnClick
/**
* Bind a method to an OnClickListener on the view for each ID specified.
* Any number of parameters from OnClickListener#onClick(android.view.View) onClick} may be used on the method.
*/
@Target(METHOD) @Retention(CLASS)
@ListenerClass(
targetType = "android.view.View",
setter = "setOnClickListener",
type = "butterknife.internal.DebouncingOnClickListener",
method = @ListenerMethod(
name = "doClick",
parameters = "android.view.View"
)
)
public @interface OnClick {
/** View IDs to which the method will be bound. */
@IdRes int[] value() default { View.NO_ID };
}

最常使用的注解的示例代码

绑定Activity

public class SimpleActivity extends AppCompatActivity {
@BindView(R.id.text_view) TextView mTextView; //this field should not be declared private or static @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ButterKnife.bind(this);// ButterKnife.bind(this) should be called after setContentView()
mTextView.setText("View视图的绑定");
} @OnClick(R.id.button)
void onButtonClick(View view) { //the method should not be declared private or static
//you can write the parameter (View view) as above or just write onButtonClick() leave parameters empty
Toast.makeText(this, "事件绑定", Toast.LENGTH_SHORT).show();
}
}

绑定Fragment

public class SimpleFragment extends Fragment {
@BindView(R.id.text_view) TextView mTextView;
private Unbinder unbinder; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);//标准写法就是这样的
unbinder = ButterKnife.bind(this, view);//绑定Activity为ButterKnife.bind(this);
mTextView.setText("TextView in Fragment are found!");
return view;
} @Override
public void onDestroyView() {
super.onDestroyView();
//Fragments have a different view lifecycle than activities.
//When binding a fragment in onCreateView, set the views to null in onDestroyView.
unbinder.unbind();//解除绑定,官方文档只对fragment做了解绑
}
}

绑定Adapter

public class PersonAdapter extends BaseAdapter {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.person_item_layout, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else holder = (ViewHolder) convertView.getTag(); holder.name.setText("包青天");
// etc... return convertView;
} static class ViewHolder {
@BindView(R.id.person_name) TextView name;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}

绑定资源

@BindView(R.id.app_name)  TextView mTextView;//view
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> nameViews; @BindString(R.string.app_name) String appName;//sting
@BindColor(R.color.red) int textColor;//颜色 @BindBitmap(R.drawable.logo) Bitmap logo;
@BindDrawable(R.drawable.selector_image) Drawable selector;//drawble
@BindDrawable(value = R.drawable.placeholder, tint = R.attr.colorAccent) Drawable tintedPlaceholder;

绑定事件

@OnClick(R.id.submit) void submit(View view) { }
@OnClick(R.id.submit) void sayHi(Button button) { } //定义一个特定类型的View时,它将自动被转换
@OnClick({ R.id.door1, R.id.door2 }) void pickDoor(DoorView door) { } //多个view在一个点击事件中回调 @OnClick(R.id.submit) void submit() { } //参数都是可选的(任何参数都是:如果不需要,可以不写)
@OnItemClick(R.id.my_list_view) void onItemClick(int position) { } //虽然有四个参数, 你可以只写你想要的那个 @OnItemLongClick(R.id.my_list_view) boolean onItmeLongClick(int position) { }//返回true时,整个touch事件结束
//if return false, the onItemClick() will be invoked反射调用 when touch up
自定义view可以绑定自己的监听,而必须指定id
public class MyButton extends Button {
@OnClick void onClick() { } //当点击自己时回调
}
添加多回调方法的监听的使用方法
@OnTextChanged(value = R.id.mEditText, callback = OnTextChanged.Callback.BEFORE_TEXT_CHANGED)
void beforeTextChanged(CharSequence s, int start, int count, int after) { } @OnTextChanged(value = R.id.mEditText, callback = OnTextChanged.Callback.TEXT_CHANGED)
void onTextChanged(CharSequence s, int start, int before, int count) { } @OnTextChanged(value = R.id.mEditText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void afterTextChanged(Editable s) { }

官方文档

Introduction

Annotate fields with @BindView and a view ID for Butter Knife to find and automatically cast the corresponding view in your layout.
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...
}
}
Instead of slow reflection, code is generated to perform the view look-ups. Calling bind delegates代表 to this generated code that you can see and debug.
代替其他库经常采用的非常慢的反射机制,ButterKnife是通过在编译时生成代码,在运行时通过执行view查找操作实现View的绑定的。当你调用 bind 方法时,代表你可以查看并调试生成的代码。

The generated code for the above example is roughly equivalent to the following:
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

You can also perform binding on arbitrary任意的 objects by supplying your own view root.
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;
}
}
Another use is simplifying the view holder pattern inside of a list adapter. 另一个用途是简化列表适配器内的 view holder 模式。
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);
}
}
}
You can see this implementation in action in the provided sample. 您可以在提供的示例中看到此实现。

Calls to ButterKnife.bind can be made anywhere you would otherwise put findViewById calls. 
可以在任何地方调用ButterKnife.bind,以取代 findViewById 的调用。

Other provided binding APIs:
  • Bind arbitrary objects using an activity as the view root. If you use a pattern like MVC you can bind the controller using its activity with ButterKnife.bind(this, activity).
  • Bind a view's children into fields using ButterKnife.bind(this). If you use <merge> tags in a layout and inflate in a custom view constructor you can call this immediately after. Alternatively或者、否则, custom view types (inflated from XML) can use it in the onFinishInflate() callback.

VIEW LISTS

You can group multiple views into a List or array.
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> nameViews;
The apply method allows you to act on对...起作用 all the views in a list at once.
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

Listeners can also automatically be configured onto methods.
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
All arguments to the listener method are optional.
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}
Define a specific type and it will automatically be cast.
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
Specify multiple IDs in a single binding for common event handling.
@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();
}
}
Custom views can bind to their own listeners by not specifying an ID.
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}

BINDING RESET

Fragments have a different view lifecycle than activities. When binding a fragment in onCreateView, set the views to null in onDestroyView. Butter Knife returns an Unbinder instance when you call bind to do this for you. Call its unbind method in the appropriate lifecycle callback.
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();
}
}

OPTIONAL BINDINGS

By default, both @Bind and listener bindings are required. An exception will be thrown if the target view cannot be found.

To suppress压制、阻止 this behavior and create an optional binding, add a @Nullable annotation to fields or the @Optional annotation to methods.

Note: Any annotation named @Nullable can be used for fields. It is encouraged鼓励 to use the @Nullable annotation from Android's "support-annotations" library.
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;

@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() { }

MULTI-METHOD LISTENERS

Method annotations whose corresponding listener has multiple callbacks can be used to bind to any one of them. Each annotation has a default callback that it binds to. Specify an alternate using the callback parameter.
@OnItemSelected(R.id.list_view) void onItemSelected(int position) { }
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED) void onNothingSelected() { }

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);
Add a static import for ButterKnife.findById and enjoy even more fun.
2017-9-22

Butter Knife 黄油刀的更多相关文章

  1. Android:Butter Knife 8.0.1配置

    github地址:https://github.com/GarsonZhang/butterknife Butter Knife Field and method binding for Androi ...

  2. [轉]Android Libraries 介紹 - Butter knife

    原文地址 Butter Knife 簡介 Butter Knife - Field and method binding for Android views.助你簡化程式碼,方便閱讀. 使用方法 開發 ...

  3. android注解[Jake Wharton Butter Knife]

    Introduction Annotate fields with @InjectView and a view ID for Butter Knife to find and automatical ...

  4. Butter Knife使用详解

    Butter Knife Github地址: https://github.com/JakeWharton/butterknife 官方说明给出的解释是 Bind Android views and ...

  5. Butter Knife 使用方法

    获取控件 @InjectView(R.id.image_show_password)ImageView image_show_password; 控件事件 @OnClick(R.id.btn_subm ...

  6. Android RoboGuice开源框架、Butter Knife开源框架浅析

    Google Guice on Android(RoboGuice) 今天介绍一下Google的这个开源框架RoboGuice, 它的作用跟之前讲过的Dagger框架差点儿是一样的,仅仅是Dagger ...

  7. android Butter Knife 使用详解

    Butter Knife github连接:https://github.com/JakeWharton/butterknife 本文使用的butterknife版本7.0.1 butterknife ...

  8. Butter Knife:一个安卓视图注入框架

    Butter Knife:一个安卓视图注入框架 2014年5月8日 星期四 14:52 官网: http://jakewharton.github.io/butterknife/ GitHub地址: ...

  9. Android Studio & Butter Knife —— 快速开发

    Butter Knife是一个Android的注解框架,可以帮助用户快速完成视图.资源与对象的绑定,完成事件的监听.(也就是少写findViewById()) 具体的介绍可以参考官方主页: http: ...

随机推荐

  1. 分布式系统的烦恼------《Designing Data-Intensive Applications》读书笔记11

    使用分布式系统与在单机系统中处理问题有很大的区别,分布式系统带来了更大的处理能力和存储容量之后,也带来了很多新的"烦恼".在这一篇之中,我们将看看分布式系统带给我们新的挑战. 1. ...

  2. Python并发编程系列之多进程(multiprocessing)

    1 引言 本篇博文主要对Python中并发编程中的多进程相关内容展开详细介绍,Python进程主要在multiprocessing模块中,本博文以multiprocessing种Process类为中心 ...

  3. 推荐:这才是你寻寻觅觅想要的 Python 可视化神器

    Plotly Express 是一个新的高级 Python 可视化库:它是 Plotly.py 的高级封装,它为复杂的图表提供了一个简单的语法. 受 Seaborn 和 ggplot2 的启发,它专门 ...

  4. 哪种写法更好?<script></script> vs/or <script type=”text/javasript”></script>

    一直很奇怪 哪种写法更好<script type=“text/javascript”>…</script> or <script>…</script>? ...

  5. grunt自动化

    1.安装模块 npm install grunt -g npm install grunt-cli -g #! --save-dev 既会把模块安装到项目node_modules下,也会安装到依赖文件 ...

  6. BZOJ 2653: middle 主席树 二分

    https://www.lydsy.com/JudgeOnline/problem.php?id=2653 因为是两个方向向外延伸所以不能对编号取前缀和(这里只有前缀和向后传递的性质,不是实际意义的和 ...

  7. 4144: [AMPPZ2014]Petrol (多源最短路+最小生成树+启发式合并)

    4144: [AMPPZ2014]Petrol Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 752  Solved: 298[Submit][Sta ...

  8. Ajax 的概念及过程?Ajax 的交互模型?同步和异步的区别?如何解决跨域问题?

    Ajax 是什么: 1)  通过异步模式,提升了用户体验 2)  优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用 3)  Ajax 在客户端运行,承担了一部分本来由服务器承担的工 ...

  9. ROS知识(14)----局部避障的动态窗口算法(DWA)及其调试的方法

    Dynamic Window Approach(DWA)是重要的局部轨迹规划算法,ROS中使用了DWA算法获得了很好的局部路径规划的效果.具体的教程可参考官方的导航调试资料Navigation Tun ...

  10. 手把手教你搭建nuget服务器

    新建web项目 工具:VS2013 版本:.Net Framework 4.6,低版本也行,不过要找到对应版本的Nuget.Server 装了NuGet客户端(百度如何安装) WebForm或MVC都 ...