android ButterKnife的简单使用
今天,簡單講講android里如何使用ButterKnife。
Android框架系列:
一.android EventBus的簡單使用
二.android Glide簡單使用
三.android OKHttp的基本使用詳解
四.android RxJava(RxAndroid)的簡單使用
五.android ButterKnife的簡單使用
?
前言:
ButterKnife是一個專注于Android系統的View注入框架,以前總是要寫很多findViewById來找到View對象,有了ButterKnife可以很輕松的省去這些步驟。是大神JakeWharton的力作,目前使用很廣。最重要的一點,使用ButterKnife對性能基本沒有損失,因為ButterKnife用到的注解并不是在運行時反射的,而是在編譯的時候生成新的class。項目集成起來也是特別方便,使用起來也是特別簡單。
?
ButterKnife 閃亮登場
ButterKnife 初識
ButterKnife,又被戲稱為黃油刀,至于為什么被戲稱為這個,大家可以看下面附上的從官方截取的icon~
一塊桌布,一個盤子,一個Android小機器人形狀的黃油,一把刀。這些合起來被大家戲稱為黃油刀。(我說呢,糾結我半天,都搞不懂黃油刀是個什么鬼,這次曉得了)
icon下面簡單解釋就是為Android 視圖(View)提供綁定字段和方法。 也就是說,我們今后可以通過這把刀去替換之前瑣碎的初始化~
?
一、 ButterKnife是啥
注解中相對簡單易懂的很不錯的開源框架
1. 強大的View綁定和Click事件處理功能,簡化代碼,提升開發效率
2. 方便的處理Adaper里的ViewHolder綁定問題
3. 運行時不會影響app效率,使用配置方便
4. 代碼清晰,可讀性強
github開源地址:
https://github.com/JakeWharton/butterknife
?
?
二、使用步驟
2.1 添加插件
File -> Settings -> Plugins -> 搜索ButterKnife,找到Android ButterKnife Zeleany進行安裝重啟AndroidStudio
?
2.2 添加依賴
在對應module的build.gradle里面添加下面的依賴,重新編譯就會自動下載
dependencies {compile 'com.jakewharton:butterknife:8.5.1'annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' }注意和Dagger2配合使用需要注意把annotationProcessor改為apt。
2.3 在Activity中使用
2.3.1 使用插件
在R.layout.activity_main上面右擊 選擇Generate -> Generate ButterKnife injections,即可選擇 生成view對應的注解,還支持ViewHolder和OnClick
2.3.2 手動
下面的代碼把R.id.tv_test這個TextView定義了為tvTest,注意類型不能為static或者private
@BindView(R.id.tv_test) TextView tvTest;//當然寫成一行也是可以 @BindView(R.id.tv_test) TextView tvTest;添加注解@OnClick(R.id.xx)即為點擊方法,對應的View參數可有可無,如果有多個參數可以只加一個參數(例如onItemClick有四個參數,你可以只加一個int position的參數)。如果參數錯誤,編譯的時候會報錯。
@OnClick(R.id.bt_test) public void onClick(View v) {tvTest.setText("被點擊了..."); }如果定義為指定的類型,將會自動轉換
@OnClick(R.id.bt_test) public void onClick(Button button) {tvTest.setText("被點擊了..."); }更多事件看下面的 三
2.4 在Fragment中使用
在Fragment中使用和在Activity中使用,只是有一點不一樣:在獲取View的時候,加多一個view參數把View綁定到ButterKnife就行了。
@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.my_fragment, container, false);//這里需要加多一個參數viewButterKnife.bind(this, view);return view; }Fragment生命周期和activity有點不同,銷毀的時候可以進行解綁
public class MyFragment extends Fragment {@BindView(R.id.bt_test)Button btTest;private Unbinder unbinder;@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.my_fragment, container, false);//綁定的時候返回了一個Unbinder對象unbinder = ButterKnife.bind(this, view);return view;}@Overridepublic void onDestroyView() {super.onDestroyView();unbinder.unbind();} }2.5 在Adapter ViewHolder中使用
把ViewHolder加一個構造方法,在new ViewHolder的時候把view傳遞進去。
static class ViewHolder {@BindView(R.id.tv_item_test)TextView tvItemTest;@BindView(R.id.bt_item_test)Button btItemTest;public ViewHolder(View view) {ButterKnife.bind(this, view);} }item里面Button控件的點擊事件也可以使用注解@OnClick來實現,在適配器里面添加就行,如:
//item的button的點擊事件@OnClick(R.id.bt_item_test)void onClick(){Toast.makeText(context,"點擊了按鈕",Toast.LENGTH_SHORT).show();}static class ViewHolder {@BindView(R.id.tv_item_test)TextView tvItemTest;@BindView(R.id.bt_item_test)Button btItemTest;public ViewHolder(View view) {ButterKnife.bind(this, view);}}注意: 如果item里面有Button等這些有點擊的控件事件的,需要設置這些控件屬性focusable為false
三、 事件注解
一共有12個
| @OnClick | 點擊事件 |
| @OnCheckedChanged | 選中,取消選中 |
| @OnEditorAction | 軟鍵盤的功能鍵 |
| @OnFocusChange | 焦點改變 |
| @OnItemClick | item被點擊(注意這里有坑,如果item里面有Button等這些有點擊的控件事件的,需要設置這些控件屬性focusable為false) |
| @OnItemLongClick | item長按(返回真可以攔截onItemClick) |
| @OnItemSelected | item被選擇事件 |
| @OnLongClick | 長按事件 |
| @OnPageChange | 頁面改變事件 |
| @OnTextChanged | EditText里面的文本變化事件 |
| @OnTouch | 觸摸事件 |
| @Optional | 選擇性注入,如果當前對象不存在,就會拋出一個異常,為了壓制這個異常,可以在變量或者方法上加入一下注解,讓注入變成選擇性的,如果目標View存在,則注入, 不存在,則什么事情都不做=如下代碼 |
?
三、綁定注解
有11種
| @BindViews | 綁定多個view id為一個view的list變量 |
| @BindView | 綁定一個view id為一個view 變量 |
| @BindArray | 綁定string里面array數組,@BindArray(R.array.city ) String[] citys ; |
| @BindBitmap | 綁定圖片資源為Bitmap,@BindBitmap( R.mipmap.wifi ) Bitmap bitmap; |
| @BindBool | 綁定真假boolean |
| @BindColor | 綁定color,@BindColor(R.color.colorAccent) int black; |
| @BindDimen | 綁定Dimen,@BindDimen(R.dimen.borth_width) int mBorderWidth; |
| @BindDrawable | 綁定Drawable,@BindDrawable(R.drawable.test_pic) Drawable mTestPic; |
| @BindFloat | 綁定float |
| @BindInt | 綁定int |
| @BindString | 綁定一個String id為一個String變量,@BindString( R.string.app_name ) String meg; |
?
五、 ButterKnife更多使用
4.1 指定多個id綁定事件
例如綁定多個Button的onclick事件,在小括號里面加大括號,然后用逗號分割即可。
@OnClick({R.id.bt_test,R.id.bt_test_two})public void onClick(View v) {switch (v.getId()){case R.id.bt_test:tvTest.setText("按鈕1被點擊了...");break;case R.id.bt_test_two:tvTest.setText("按鈕2被點擊了...");break;}}4.2 多個view
使用BindViews綁定多個
@BindViews({R.id.tv_test,R.id.tv_test_two,R.id.tv_test_three}) List<TextView> tvList;使用Action接口或者Setter接口或者View的Property,可以同時設置多個view的屬性
@BindViews({R.id.tv_test,R.id.tv_test_two,R.id.tv_test_three}) List<TextView> tvList;@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);//設置多個view的屬性//方式1 傳遞值ButterKnife.apply(tvList,ENABLED,false);//方式2 指定值ButterKnife.apply(tvList,DISABLE);//方式3 設置View的PropertyButterKnife.apply(tvList, View.ALPHA, 0.0f);}//Action接口設置屬性 static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {@Override public void apply(View view, int index) {view.setEnabled(false);} };//Setter接口設置屬性 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);} };4.3 自定義View使用注解事件
不用指定id,直接注解OnClick
public class MyButton extends Button {@OnClickpublic void onClick() {} }4.4 綁定api
使用Activity為根視圖綁定任意對象時,如果你使用類似MVC的設計模式你可以在Activity 調用ButterKnife.bind(this, activity),來綁定Controller。
使用ButterKnife.bind(this)綁定一個view的子節點字段.如果你在子View的布局里或者自定義view的構造方法里 使用了inflate,你可以立刻調用此方法。或者,從XML inflate來的自定義view類型可以在onFinishInflate回調方法中使用它。
4.5 多方法的listener
例如Spinner的setOnItemSelectedListener,他會回調兩個方法:
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {}@Overridepublic void onNothingSelected(AdapterView<?> parent) {} });所以這時候如果我們需要注解onNothingSelected,需要在注解參數添加一個callback
@OnItemSelected(R.id.my_spiner)//默認callback為ITEM_SELECTED void onItemSelected(int position) {Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show(); }@OnItemSelected(value = R.id.my_spiner, callback = OnItemSelected.Callback.NOTHING_SELECTED) void onNothingSelected() {Toast.makeText(this, "Nothing", Toast.LENGTH_SHORT).show(); }注意的是Spinner中只要有數據,默認都會選中第0個數據,所以想進入到onNothingSelected()方法,就需要把Adapter中的數據都清空
?
4.6 使用findById
Butter knife仍然包含了findById方法,用于仍需從一個view ,Activity,或者Dialog上 find view的時候。并且它可以自動轉換類型。
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);4.7 代碼混淆(這個不用理解,知道有這個功能就行,因為我也沒有明白)
-keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; }-keepclasseswithmembernames class * {@butterknife.* <fields>; }-keepclasseswithmembernames class * {@butterknife.* <methods>; }?
五、 原理
利用了IOC的(Inverse of Controll)控制反轉結構,04年后改名為DI(dependency injection)依賴注入。目的是為了使類與類之間解耦合,提高系統的可擴展性和可維護性。
?
六、 和Dagger使用注意
搭配Dagger使用的時候,ButterKnife可能會不起作用,沒效果,綁定控件為null。這時候把依賴包的annotationProcessor改為apt 就可以了:
compile 'com.jakewharton:butterknife:8.5.1'//aptapt 'com.jakewharton:butterknife-compiler:8.5.1'?
好了,ButterKnife的基本使用就到這里的。如果只是想知道怎么使用,看到這里就可以了。下面會講講具體的原理代碼,對能力有一定的要求,大家自己決定看不看。
?
ButterKnife 語法
1. activity fragment 綁定與 fragment解綁
想要使用ButterKnife,簡單配置之后,我們還需要在Activity中onCreate()綁定,如下:
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 必須在setContentView()之后綁定ButterKnife.bind(this); }而如果使用fragment,官方給出的綁定以及解綁如下:
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();} }綁定之后,我們一起來看看,常用的幾種監聽通過使用ButterKnife之后,我們又該如何編寫相關事件呢?別急,往下看~
2.單擊事件
首先我們先看看人家表層提供我們代碼中,我們可以得到哪兒些對我們有用的信息
首先明確,targetType(目標類型)為View,setter為setOnClickListener(單擊事件監聽),type為ButterKnife封裝的單擊事件(butterknife.internal.DebouncingOnClickListener),而method中則是name為doClick以及parameters為View類型的倆個參數;而下面的interface接口中需要我們傳遞一個id。
簡單了解后,我們衍生出三種寫法,如下:
// 寫法1@OnClick(控件ID)void 方法名() {//業務邏輯操作}// 寫法2@OnClick(控件ID)void 方法名(控件類型) {//業務邏輯操作}// 寫法3@OnClick(控件ID)void 方法名(View view) {//業務邏輯操作}你可以按照上面指定一個個的寫,也可以綁定多個,如官網提供下面寫法
3.長按事件
同樣依舊看人家怎么寫的,看看我們能了解到什么
和單擊事件對比,長按時間則多出了一個returnType(返回值),且默認為false。So,寫法如下~
// 方法1@OnLongClick(控件ID)boolean 方法名(){// 業務邏輯操作return false;}// 方法2@OnLongClick(控件ID)boolean 方法名(控件類型){// 業務邏輯操作return false;}// 方法3@OnLongClick(控件ID)boolean 方法名(View view){// 業務邏輯操作return false;}4.Checked改變事件
老規矩:
改變,一般來說,會提供我們一個標識,去方便我們根據不同的狀態去處理不同的邏輯,so…
// 寫法1@OnCheckedChanged(控件ID)void radioButtonCheckChange(boolean isl) {// 業務邏輯}// 寫法2@OnCheckedChanged(控件ID)void radioButtonCheckChange(控件類型,boolean isl) {// 業務邏輯}5.監聽軟鍵盤右下角按鈕事件
老規矩:
so…經過上面幾個大家可以知道,我們只需要對parameters以及是否是returnType重點關注即可。
// 寫法1@OnEditorAction(控件ID)boolean 方法名() {// 業務邏輯操作return false;}// 寫法2// code:狀態碼@OnEditorAction(控件ID)boolean EditTextAction(int code) {// 業務邏輯操作return false;}// 寫法3// KeyEvent@OnEditorAction(控件ID)boolean EditTextAction(KeyEvent keyEvent) {// 業務邏輯操作return false;}// 寫法4@OnEditorAction(控件ID)boolean EditTextAction(int code, KeyEvent keyEvent) {// 業務邏輯操作return false;}// 寫法5@OnEditorAction(控件ID)boolean EditTextAction(TextView textView,int code, KeyEvent keyEvent) {// 業務邏輯操作return false;}6. EditText內容改變監聽事件
由于源碼中內容較長,不方便截圖,故截取部分代碼做解析,如下:
@Target(METHOD) @Retention(CLASS) @ListenerClass(targetType = "android.widget.TextView",setter = "addTextChangedListener",remover = "removeTextChangedListener",type = "android.text.TextWatcher", ---> 這里同樣對之前的TextWatcher做了相關處理 gggcallbacks = OnTextChanged.Callback.class ---> 自定義枚舉,通過枚舉類型標識當前操作 666 ) public @interface OnTextChanged {/** View IDs to which the method will be bound. */@IdRes int[] value() default { View.NO_ID }; ---> 需要傳入ID/** Listener callback to which the method will be bound. */Callback callback() default Callback.TEXT_CHANGED; ---> 未改變狀態/** {@link TextWatcher} callback methods. */enum Callback { ---> 枚舉中分為三種類似 未改變 改變前 改變后/** {@link TextWatcher#onTextChanged(CharSequence, int, int, int)} */@ListenerMethod(name = "onTextChanged", ---> 當前標識為 未改變parameters = {"java.lang.CharSequence", ---> 用戶輸入字符"int", ---> 改變前個數"int", ---> 測試時,返回0,沒整明白代表什么意思"int" ---> 根據打印結果,猜測這個應該是每次增加內容個數})TEXT_CHANGED,/** {@link TextWatcher#beforeTextChanged(CharSequence, int, int, int)} */@ListenerMethod(name = "beforeTextChanged", ---> 當前標識為 改變前parameters = {"java.lang.CharSequence", ---> 用戶輸入字符"int", ---> 改變前個數"int","int"})BEFORE_TEXT_CHANGED,/** {@link TextWatcher#afterTextChanged(android.text.Editable)} */@ListenerMethod(name = "afterTextChanged", ---> 當前標識為 改變后parameters = "android.text.Editable" ---> 用戶輸入字符)AFTER_TEXT_CHANGED, ---> 我們關注的重點在此,每次只需要監聽這個,去做相關處理即可}從上得知,關于EditText內容改變事件,我們關注點只在乎改變后的內容格式(個數)是否符合項目需求,而其他可以暫時忽略,從而衍生下面寫法:
// 內容改變后監聽// Editable editable:用戶輸入字符@OnTextChanged(value = 控件ID, callback = 監聽類型,改變后取值為:OnTextChanged.Callback.AFTER_TEXT_CHANGED)void editTextChangeAfter(Editable editable) {// 業務邏輯}// 內容改變前監聽@OnTextChanged(value = 控件ID, callback = 監聽類型,改變前取值為:OnTextChanged.Callback.BEFORE_TEXT_CHANGED)void editTextChangeBefore(CharSequence s, int start) {// 業務邏輯}// 內容未發生改變監聽@OnTextChanged(value = 控件ID, callback = 監聽類型,取值為:OnTextChanged.Callback.TEXT_CHANGED)void editTextChange(CharSequence s, int start) {// 業務邏輯}7. 焦點監聽事件
老規矩:
由此可見,如下:
@OnFocusChange(控件ID)void editTextFocus(boolean isl){// 業務邏輯}8. 觸摸監聽事件
老規矩:
寫法如下:
@OnTouch(控件ID)boolean imageView(MotionEvent event){// 業務邏輯return false;}?
9. item項單擊監聽事件
老規矩:
so…
@OnItemClick(控件ID)void listItemClick(int position){// 業務邏輯}10. item項長按監聽事件
老規矩:
so…
@OnItemLongClick(R.id.listView)boolean listItemLongClick(int position) {Toast.makeText(this, "OnItemLongClick---點擊了第" + position + "個", Toast.LENGTH_SHORT).show();return true;}?
簡單總結一下,ButterKnife就是一個框架,用注解來取代了findviewbyid的功能,而且它是編譯器完成的,對于運行沒有任何的效率的影響。使用ButterKnife最好是下載對應的插件Android ButterKnife Zelezny,具體怎么下載,我下一步博客再講。
?
android ButterKnife的簡單使用就講完了。
?
就這么簡單。
總結
以上是生活随笔為你收集整理的android ButterKnife的简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android RxJava(RxAnd
- 下一篇: android 解决错误:Intel H