使用 Butterknife 绑定 Android 中的 View 对象

Android ButterKnife 库是一个视图注入库,它使用注解将视图注入 android activity/fragment。例如,@BindView 批注通过自动类型转换视图元素来替代使用 findViewById() 方法。

不仅仅是视图绑定,butterknife 还提供了许多其他有用的选项,比如绑定字符串、调光、绘图、单击事件等等。我们将简要介绍本文中提供的每个组件。

添加 ButterKnife 依赖

您要做的第一件事是,通过在项目的 app/build.gradle 文件中添加以下依赖项,在项目中添加 ButterKnife。添加完成后,同步你的项目,你就可以开始了。

dependencies {
    ...
 
    // butter knife
    compile 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

基本用法

一旦添加了依赖项,所有 ButterKnife 注释都可以导入。首先,我们将看到如何使用 @BindView@OnClick 注释。假设您的 Activity 有如下布局,其中有一个 TextView 和一个 Button。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <TextView
        android:id="@+id/lbl_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enter your email"
        android:textAllCaps="true" />

    <EditText
        android:id="@+id/input_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_enter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dimen_20"
        android:text="@string/enter" />
</LinearLayout>

为了使 视图 View 在 Activity 中可用,我们需要执行以下步骤。

第一步:在声明视图变量的同时(例如 TextView mTextView ) 使用 @BindView 注释,注意不要使用 private 修饰视图变量。

第二步:在 onCreate() 方法中的 setContentView() 后面调用 ButterKnife.bind(this)。

就这样,视图注入发生了,不再需要使用 findViewById() 方法对视图变量进行类型转换。您还可以看到,只需在方法之前添加 @OnClick 注释,就可以附加 click 事件。

public class MainActivity extends AppCompatActivity {
 
    @BindView(R.id.lbl_title)
    TextView lblTitle;
 
    @BindView(R.id.input_name)
    EditText inputName;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // bind the view using butterknife
        ButterKnife.bind(this);
    }
 
    @OnClick(R.id.btn_enter)
    public void onButtonClick(View view) {
        Toast.makeText(getApplicationContext(), "You have entered: " + inputName.getText().toString(),
                Toast.LENGTH_SHORT).show();
    }
}

在 Fragment 中使用

在 Fragment 中使用视图注入与 Activity 相同,只是 ButterKnife.bind() 方法改变了。除了目标参数之外,我们还需要注入视图对象作为参数传递。由于 Fragment 的生命周期方法,您还必须使用 Unbinder 解除onDestroyView() 中的视图绑定。

下面是在 Fragment 中使用 ButterKnife 的例子。

public class MyFragment extends Fragment {
 
    Unbinder unbinder;
 
    @BindView(R.id.lbl_name)
    TextView lblName;
 
    @BindView(R.id.btn_enter)
    Button btnEnter;
 
    @BindView(R.id.input_name)
    EditText inputName;
 
    public MyFragment() {
        // Required empty public constructor
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
    }
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_my, container, false);
 
        // bind view using butter knife
        unbinder = ButterKnife.bind(this, view);
 
        return view;
    }
 
    @Override
    public void onDestroyView() {
        super.onDestroyView();
 
        // unbind the view to free some memory
        unbinder.unbind();
    }
}

在列表适配器中使用

ButterKnife 也可以用于列表适配器中。下面是 @BindView 在 recyclerview’s 的适配器类中的例子。

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.MyViewHolder> {
 
    private List<Contact> contacts;
 
    public class MyViewHolder extends RecyclerView.ViewHolder {
 
        @BindView(R.id.name)
        TextView name;
 
        @BindView(R.id.mobile)
        TextView mobile;
 
        public MyViewHolder(View view) {
            super(view);
 
            // binding view
            ButterKnife.bind(this, view);
        }
    }
 
    public ContactsAdapter(List<Contact> contacts) {
        this.contacts = contacts;
    }
 
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.contact_list_row, parent, false);
 
        return new MyViewHolder(itemView);
    }
 
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Contact contact = contacts.get(position);
        holder.name.setText(contact.getName());
        holder.mobile.setText(contact.getMobile());
    }
 
    @Override
    public int getItemCount() {
        return contacts.size();
    }
}

与字符串、颜色、尺寸、图片资源等一起使用。

除了绑定视图元素之外,您还可以绑定其他资源,比如字符串(@BindString)、颜色(@BindColor)、尺寸(@BindDimen)和可绘制资源(@BindDrawable)。下面的示例演示了多种注释及其用法。

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.logo)
    ImageView imgLogo;
 
    @BindView(R.id.lbl_title)
    TextView lblTitle;
 
    @BindDrawable(R.mipmap.ic_launcher)
    Drawable drawableLogo;
 
    @BindColor(R.color.colorPrimaryDark)
    int colorTitle;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // bind the view using butterknife
        ButterKnife.bind(this);
 
        // setting label color
        lblTitle.setTextColor(colorTitle);
 
        // displaying logo using drawable
        imgLogo.setImageDrawable(drawableLogo);
    }
}

添加点击事件监听

我们已经看到了 @OnClick 注释的例子,但是下面是函数参数的几个变体。

// click event with source view params
@OnClick(R.id.btn_enter)
public void onButtonClick(View view) {
    Toast.makeText(getApplicationContext(), "You have entered: " + inputName.getText().toString(),
            Toast.LENGTH_SHORT).show();
}
 
 
// click event without params
@OnClick(R.id.btn_enter)
public void onButtonClick() {
    Toast.makeText(getApplicationContext(), "You have entered: " + inputName.getText().toString(),
            Toast.LENGTH_SHORT).show();
}
 
 
// click event with specific type param
@OnClick(R.id.btn_enter)
public void onButtonClick(Button button) {
    Toast.makeText(getApplicationContext(), "You have entered: " + inputName.getText().toString(),
            Toast.LENGTH_SHORT).show();
}

多个视图放进集合批量操作

在某些情况下,您可能希望对视图组(一组视图)应用某些操作,例如应用颜色,设置文本或一次选择所有复选框。使用 ButterKnife 可以很容易地做到这一点。只需使用 @BindViews 注释将所有视图存储到一个 List 中,并使用 ButterKnife.Action() 方法对所有视图应用一些操作。

在下面的示例中,对 TextView 组应用了两个操作。首先,文本是从字符串数组中设置的。其次,对列表中的所有 TextView 应用一种颜色。

public class MainActivity extends AppCompatActivity {
    @BindColor(R.color.colorPrimaryDark)
    int colorTitle;
 
    @BindViews({R.id.lbl1, R.id.lbl2, R.id.lbl3})
    List<TextView> lblArray;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // bind the view using butterknife
        ButterKnife.bind(this);
 
        final String[] lblText = new String[]{"Cat", "Dog", "Rat"};
 
        ButterKnife.Action<TextView> APPLY_TEXT = new ButterKnife.Action<TextView>() {
            @Override
            public void apply(TextView view, int index) {
                view.setText(lblText[index]);
            }
        };
 
        // setting text to array of labels
        ButterKnife.apply(lblArray, APPLY_TEXT);
 
        // Applying color to group of labels
        ButterKnife.Action<TextView> APPLY_COLOR = new ButterKnife.Action<TextView>() {
            @Override
            public void apply(@NonNull TextView view, int index) {
                view.setTextColor(colorTitle);
            }
        };
 
        ButterKnife.apply(lblArray, APPLY_COLOR);
    }
}

注解表

下面是 ButterKnife 提供的注释列表及其用法。

AnnotationDescription
@BindViewBinds view object. TextView, Button, Spinner or any view object

@BindView(R.id.logo)
ImageView imgLogo;
@BindViewsBinds array of views into List

@BindViews({R.id.lbl_name, R.id.lbl_email, R.id.lbl_address})
List lblArray;
@BindDrawableBinds drawable element. Loads the drawable image from res folder

@BindDrawable(R.mipmap.ic_launcher)
Drawable drawableLogo;
@BindStringBinds string resource

@BindString(R.string.app_name)
String appName;
@BindColorBinds color resource

@BindColor(R.color.colorPrimaryDark)
int colorTitle;
@BindDimenBinds dimen resource

@BindDimen(R.id.padding_hori)
float paddingHorizontal;
@BindAnimBinds animation from anim resource

@BindAnim(R.anim.move_up)
Animation animMoveUp;
@BindBitmapBinds bitmap object.

@BindBitmap(R.mipmap.ic_launcher)
Bitmap logo;
@BindFontBinds font resource

@BindViews({R.id.lbl_name, R.id.lbl_email, R.id.lbl_address})
List lblArray;
@BindFloatBinds float value

@BindFloat(R.dimen.radius)
float radius;
@BindIntBinds int resource

@BindInt(R.integer.distance)
int distance;

我希望我们已经涵盖了 ButterKnife 的大部分功能。如果您认为还有什么需要添加的,让我们在下面的评论部分进行讨论。