1. 程式人生 > >[Android]ButterKnife-無盡之刃-繫結檢視控制元件和事件的快速開發工具

[Android]ButterKnife-無盡之刃-繫結檢視控制元件和事件的快速開發工具

簡單介紹

Butter knife是大神JakeWharton的一款Android利器,多數開發者都應該瞭解和使用過,這把黃油刀最大的吸引人的地方就是簡化了android程式編寫中的view,findviewById(id)和setOnxxxListener事件的寫法,它使用了一種很簡潔的註解寫法,例如

會發現沒有了findviewById這種超累的程式碼片段了,哈哈,這就值得讓我們為這把黃油刀點贊!

簡單使用

1.先下載butterknife的jar包,本文示例程式碼用的是版本7.0.1,可能與舊版本有些方法名不一樣。如果用的是as:直接用gradle:

compile 'com.jakewharton:butterknife:7.0.1'

@bind方式就是簡化了findviewbyid的程式碼,但在使用之前,一定要在Acivity中初始化Butterknife.bind(activity)。

先上本地demo的activity_main.xml,你可以直接跳過這段,沒有具體的內容,主要是看這麼引用這些控制元件的id.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".ExampleActivity">

    <LinearLayout
        android:id="@+id/layout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/app_title_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="123"
            android:gravity="center"
            android:textSize="20sp" />

        <Button
            android:id="@+id/bind_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/bind_me" />

        <TextView
            android:id="@+id/text_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@string/cool_text"
            android:textSize="20sp"
            android:visibility="invisible" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/layout1"
        android:background="#ADE8BA"
        android:orientation="vertical">

        <fragment
            android:id="@+id/example_fragment"
            android:name="org.jan.butterknife.demo.ExampleFragment"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</RelativeLayout>
ExampleActivity,先看看我們怎麼使用butter knife獲取控制元件引用,以及快速註冊點選事件的。
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import butterknife.Bind;
import butterknife.BindString;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;

import static android.widget.Toast.LENGTH_SHORT;

/**
 * butterknife的簡單使示例程式碼
 */
public class ExampleActivity extends AppCompatActivity {
    /**
     * 2:7.0+版本的butterKnife將使用bind註解
     * 注:因為註解用到了反射機制,所以這裡的所有用到butterKnife的註解的變數都是非private的
     */
    @Bind(R.id.bind_btn)
    Button button;
    @Bind(R.id.text_content)
    TextView mCoolText;
    @Bind(R.id.app_title_text)
    TextView mTitleText;

    //繫結預定義的字串資源,還有其他的一些方法如:@BindBool, @BindColor, @BindDimen, @BindDrawable, @BindInt
    @BindString(R.string.butterknife_demo)
    String title;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.將繫結該Activity
        ButterKnife.bind(this);
        //3.已經不再需要一個個findviewbyid了,可以直接呼叫,非常省心
        userFieldToDo();
    }

    private void userFieldToDo() {
        button.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
        mTitleText.setText(title);
        mCoolText.setText("bind textview");
    }

    /**
     * 
[email protected]
可以根據view's id來註冊一個點選事件 * 方法引數是可選的,可以傳一個view,或者widget, * 這裡是無參的,你可以寫成onClickBindButton(View view)或onClickBindButton(Button btn) */ @OnClick(R.id.bind_btn) void onClickBindButton() { mCoolText.setVisibility(View.VISIBLE); Toast.makeText(this, "I bind it!", LENGTH_SHORT).show(); } /** * 繫結長按事件,這裡要有返回一個boolean值,預設為false * @return */ @OnLongClick(R.id.bind_btn) boolean onLongClickBindButton(){ Toast.makeText(this, "Let me go!", LENGTH_SHORT).show(); return true; } @Override public void onBackPressed() { super.onBackPressed(); finish(); } }
其實就是兩個步驟:1.初始化butterknife
  2.bind所需要的widget
  3.在fragment中的話可以選擇解除繫結。
這樣寫到底有沒有用呢?看看效果吧,別搞了半天還是奔潰的。
果然是可行的,好東西果斷要分享啊!
2.可能有人會有疑問,在Activity中這樣做是可行的,但如果換在Fragment中或者listview的Adapter中,是否也可以用butterknife來簡化程式碼呢,答案是肯定可以的。
**
 * 在fragment中的butterknifey運用
 */
public class ExampleFragment extends Fragment {
//    @Bind(R.id.fragment_title)
    TextView mTitleText;
    @Bind(R.id.example_listview)
    ListView mListview;

    public ExampleFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_example, container, false);
        //1.bind方法很是很靈活的
        ButterKnife.bind(this, view);
        //2.如果遇到必須要利用findviewbyid的方式來引用某個view的話,你可以使用下面這種方式
        mTitleText = ButterKnife.findById(view,R.id.fragment_title);
        mTitleText.setGravity(Gravity.CENTER_HORIZONTAL);
        mTitleText.setText("Example Fragment");
        SimpleAdapter adapter = new SimpleAdapter(getContext());
        mListview.setAdapter(adapter);
        return view;
    }
    //給listview註冊了一個onItemClick事件,這裡的會傳入一個position
    @OnItemClick(R.id.example_listview)
    void onItemClick(int position){
        String item = mListview.getAdapter().getItem(position).toString();
        Toast.makeText(getContext(),"i clicked "+item,Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        //2.解除繫結
        ButterKnife.unbind(this);
    }
}
fragment_example.xml 這是fragment的佈局檔案,就是展示一個簡單的listview.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="org.jan.butterknife.demo.ExampleFragment">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/fragment_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <ListView
            android:id="@+id/example_listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="#FFFFFF"
            android:dividerHeight="1dp" />
    </LinearLayout>

</FrameLayout>

Listview使用的SimpleAdapter.java
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import butterknife.Bind;
import butterknife.BindDrawable;
import butterknife.ButterKnife;

public class SimpleAdapter extends BaseAdapter {
  private static final String[] CONTENTS =
      "誰也 跟不上 我的 節奏 德瑪西亞 啦啦 啦啦啦".split(" ");

  private final LayoutInflater inflater;

  public SimpleAdapter(Context context) {
    inflater = LayoutInflater.from(context);
  }

  @Override public int getCount() {
    return CONTENTS.length;
  }

  @Override public String getItem(int position) {
    return CONTENTS[position];
  }

  @Override public long getItemId(int position) {
    return position;
  }

  @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.simple_list_item, parent, false);
      holder = new ViewHolder(view);
      view.setTag(holder);
    }
    String s = getItem(position);
    holder.word.setText(s);
    holder.imageView.setBackground(holder.defaultImage);
    return view;
  }

  /**
   * 看ViewHolder的變數就知道我們又省去在getview方法裡不停的findviewbyid了
   */
  static class ViewHolder {
    @Bind(R.id.hehe_image)
    ImageView imageView;
    @Bind(R.id.hehe_text)
    TextView word;
    @BindDrawable(R.drawable.main_icon_service)
    Drawable defaultImage;

    ViewHolder(View view) {
      //這裡黃油刀在建構函式中久把fragment中的檢視綁定了
      ButterKnife.bind(this, view);
    }
  }
}
simple_list_item.xml 這是list_item的佈局。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/hehe_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/hehe_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="test"
        android:textSize="16sp" />
</LinearLayout>


還有一些事件的寫法我這裡就不一一舉例了。詳細的使用我們可以看--->DOC<-----
最後,謝謝閱讀。