Butterknife系列一:史上最全的android中Butterknife的使用

史上最全的android中Butterknife的使用


提示:
博主:章飞 _906285288的博客
博客地址:http://blog.csdn.net/qq_29924041


Butterknife是什么?

  是由国外一个大牛开源出来的一个项目,是为了用过注解的形式来在android中绑定view以及事件信息。 目前在github上面的开源地址为
https://github.com/JakeWharton/butterknife
有兴趣的可以看看


Butterknife的好处

  1. 强大的View绑定事件和资源文件的绑定
  2. 使用的便捷性上,剔除了原始绑定时候的复杂性
  3. 由于大多数的注解都是在编译期,所以不会影响程序运行的效率
  4. 代码清晰,可读性相对来说要强很多

怎么使用Butterknife?

插件的添加和库的依赖

插件的添加

    File -> Settings -> Plugins -> 搜索ButterKnife,找到Android ButterKnife Zeleany进行安装重启AndroidStudio 

这里写图片描述

库的依赖

如果想要去使用Butterknife,肯定是要去进行库的依赖的吧
    compile 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
认识Butterknife的注解类型

Butterknife最新的版本中,为我们提供了总共有25个注解。其中分成两类,一个是资源的绑定形式,另外一种就是事件监听的类型

绑定注解,视图,资源,等等,一共13个
名称解析
@BindViews绑定多个view id 为一个view的list变量 @BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> nameViews;
@BindView绑定一个view id为一个view变量@BindView(R.id.title) TextView title;
@BindArray绑定String中的array数组 @BindArray(R.array.city)String[] citys;
@BindBitmap绑定图片资源文件, @BindBitmap(R.mipmap.wifi) Bitmap bitmap;
@BindBool绑定真假boolean @BindBool(R.bool.boor)
@BindColor绑定颜色 @BindColor(R.color.red)
@BindDimen绑定尺寸 @BindDimen(R.dimen.spacer) Float spacer;
@BindDrawable绑定Drawable @BindDrawable(R.drawable.graphic) Drawable graphic
@BindFloat绑定Float
@BindInt绑定Int
@BindString绑定一个String id为String变量, @BindString(R.string.app_name) String msg
@BindAnim绑定动画
@BindFont绑定字体文字
绑定事件,一共有12个事件监听
名称解析
@OnClick点击事件
@OnCheckedChanged选中,选中取消
@OnEditorAction软键盘的功能按键
@OnFocusChange焦点改变
@OnItemClickItem被点击事件(注意这里有坑,如果item里面有Button等这些有点击的控件事件的,需要设置这些控件属性focusable为false)
@OnItemLongClicktem长按,返回真则可以拦截onItemClick
@OnItemSelectedItem被选择事件
@OnLongClick长按事件
@OnPageChange页面改变事件
@OnTextChangedEditText里面的文本变化事件
@OnTouch触摸事件
@Optional选择性注入,如果当前对象不存在,就会抛出一个异常,为了压制这个异常,可以在变量或者方法上加入一下注解,让注入变成选择性的,如果目标View存在,则注入, 不存在,则什么事情都不做=如下代码
ButterKnife在Activity中的使用方式
数据绑定标签13个,Bind系列

@BindAnim
使用方式如下所示:

@BindAnim(R.anim.fade_in) Animation fadeIn;

@BindArray
使用方式如下所示:
由于数组资源文件中的数组可以定义成多种数据类型,因此使用方式如下所示

1:String array
    //数组:
    <string-array name="countries">
        <item>中国</item>
        <item>日本</item>
</string-array>
    @BindArray(R.array.countries) String[] countries;
2:Int array
    //数组:
    <integer-array name="phones">
        <item>12345</item>
        <item>43534</item>
    </integer-array>
    @BindArray(R.array.phones) int [] phones
3:Text array
    //数组:与stringArray类似
    <string-array name="countries">
        <item>中国</item>
        <item>日本</item>
    </string-array>
    @BindArray(R.array.options) CharSequence[] options;

4:Type array ----->android.content.res.TypeArray
    //数组,TypeArray中是一种混合类型形式,所以相对比较复杂一点:
    <string-array name="feed_icons">
        <item>@color/colorAccent</item>
        <item>@dimen/dp_72</item>
        <item>@drawable/leak_canary_icon</item>
        <item>@drawable/flashligth_drawable_btn</item>
        <item>@drawable/ic_launcher_background</item>
        <item>@layout/encode</item>
    </string-array>
    @BindArray(R.array.icons) TypedArray icons;

@BindBitmap
绑定图片操作

@BindBitmap(R.drawable.logo) Bitmap logo;
@BindBitmap(R.mipmap.ic_launcher) Bitmap mBitmap;

@BindBool
绑定boolean类型的值

//首先要在资源文件中定义bool,
<bool name="isRun" >true</bool>

@BindBool(R.bool.isRun) Boolean isRun;
//不过一般情况下是不这样进行使用的

@BindColor
绑定颜色的操作,同样颜色可以绑定一个单一的颜色,同样也可以绑定颜色的组合形式,

//绑定单一颜色:
//定义颜色类型:
<color name="colorAccent">#FF4081</color>
@BindColor(R.color. colorAccent) int colorAccent;

//绑定颜色组合:使用ColorStateList类进行操作,定义一个button_view的selector
<?xml version="1.0" encoding="utf-8"?>  
<selector xmlns:android="http://schemas.android.com/apk/res/android">  
            <item android:state_pressed="true"  
          android:color="#ffff0000"/> <!-- pressed -->  
        <item android:state_focused="true"  
          android:color="#ff0000ff"/> <!-- focused -->  
            <item android:color="#ff000000"/> <!-- default -->  
</selector>

//这样就可以绑定ColorStateList,然后通过空间的setTextColor进行设置
@BindColor(R.color. button_view) ColorStateList greenSelector

@BindDimen

绑定尺寸,尺寸有int类型和float类型

@BindDimen(R.dimen.sp_20) int gapxp;
@BindDimen(R.dimen.sp_20) float gapsp;

@BindDrawable
Drawable的绑定

@BindDrawable(R.drawable.placeholder) Drawable placeholder
//还有另外一种形式,即drawable与attr共同使用,attr为特性,tint为着色的意思
@BindDrawable(value = R.drawable.placeholder, tint = R.attr.colorAccent) 
Drawable tintedPlaceholder;

@BindFloat 绑定float类型

<item name="whatever" format="float" type="dimen">1.1</item>
<item name="twelve_point_two" format="float" type="dimen">12.2</item>
    BindFloat(R.dimen.image_ratio) float imageRatio
BindFloat(R.dimen. twelve_point_two) float twelve_point_two

@BindFont
绑定的是字体样式

BindFont(R.font.comic_sans) Typeface comicSans;
通过setTypeFace的形式进行设置样式

@BindInt
绑定int类型

BindInt(R.int.columns) int columns;

@BindString
绑定String类型的资源

@BindString(R.string.app_name) String appName;

@BindView
将控件的id与视图进行绑定操作

@BindView(R.id.showArrayText)  TextView mView;

@BindViews

BindViews其实是BindView的一种扩展形式,主要适用于有多个相同的view的时候,这个时候可以使用BindViews将其装装载在一个集合/数组中,这样在使用的时候,直接通过下标的形式进行使用

BindViews({ R.id.title, R.id.subtitle }) List<TextView> titlesList;
BindViews({ R.id.title, R.id.subtitle }) TextView [] titlesArray;
//然后通过titlesList.get(1)或者titlesArray [1]来进行获取
事件触发注解标签的使用形式,12个On系列

@ OnCheckedChanged
这个属性主要是针对类似RadioButton,CheckedBox,其父类为CompoudButton类型的控件
主要可以有以下三种形式:注意:函数名字其实是可以随机取值的,只是形式参数有两种形式

//第一种:形式参数中只有一个boolean
@OnCheckedChanged(R.id.checkBox)
    void onChecked(boolean isChecked){
        Toast.makeText(this, "checkBox:"+isChecked, Toast.LENGTH_SHORT).show();
}

//第二种:形式参数中有控件CompoundButton和boolean
@OnCheckedChanged(R.id.checkBox2)
void onCheckedChanged(CompoundButton compoundButton,boolean isChecked){
        Toast.makeText(this, "compoundButton111:"+compoundButton+"\tcheckBox:"+isChecked, Toast.LENGTH_SHORT).show();
}

//第三种形式为ID具有两个,这个时候如果没有视图绑定,默认是会进行绑定操作的
@OnCheckedChanged({R.id.checkBox3,R.id.checkBox4})
void onCheckedChanged2(CompoundButton compoundButton,boolean isChecked){
        Toast.makeText(this, "compoundButton2222:"+compoundButton+"\tcheckBox:"+isChecked, Toast.LENGTH_SHORT).show();
}

@ OnClick
OnClick很简单,其实也就是点击事件,只是在ButterKnife中点击事件中的参数可以没有,也可以有一个View类型,,没有绑定View,也可以生效

@OnClick(R.id.example) 
    void onClick() {
        Toast.makeText(this, "Clicked!", Toast.LENGTH_SHORT).show();
    }

@OnClick({R.id.topText,R.id.bottom_text})
    void onTextViewClick(View mView){
        Toast.makeText(BufferKnifeDemoActicity.this,((TextView)mView).getText().toString(),Toast.LENGTH_LONG).show();
}

//如果是在自定义view中,类似,这个时候,就不用指定具体的ID了。
Class customBtn extends Button{
        @Onclick
        public void onClick(View view){
    }
}

@ OnEditorAction
OnEditorAction主要是针对EditText来说的,需要注意的是 setOnEditorActionListener这个方法,并不是在我们点击EditText的时候触发,也不是在我们对EditText进行编辑时触发,而是在我们编辑完之后点击软键盘上的回车键才会触发
因为EditText是继承自TextView,因此在实际过程中,也是可以有TextView返回的

@OnEditorAction(R.id.example) boolean onEditorAction(KeyEvent key) {
    Toast.makeText(this, "Pressed: " + key, Toast.LENGTH_SHORT).show();
    return true;
 }

@OnEditorAction(R.id.example) boolean onEditorAction(TextView mTextView,int actionId,KeyEvent key) {
    Toast.makeText(this, "Pressed: " + key, Toast.LENGTH_SHORT).show();
    return true;
 }

//其具体使用的方式可以参考OnEditorActionListener的使用

@ OnFocusChange

此注解主要是来源于setOnFocusChangeListener,即其主要的作用同样也是针对EditText来进行使用的

@OnFocusChange(R.id.example) void onFocusChanged(boolean focused) {
        Toast.makeText(this, focused?"Gainedfocus": "Lost focus", Toast.LENGTH_SHORT).show();
  }

//同时还有一种两个参数是的函数形式
@OnFocusChange(R.id.example) void onFocusChanged(View mView,boolean focused) {
        Toast.makeText(this, focused?"Gainedfocus": "Lost focus", Toast.LENGTH_SHORT).show();
 }

@ OnItemClick
这个注解主要是针对AdapterView,即类似ListView这样的控件使用的事件类型,貌似在实际RecycleView不是继承与AdapterView,因此不能使用此注解

//第一种形式:参数只有一个position
    @OnItemClick(R.id.example_list) void onItemClick(int position) {
        Toast.makeText(this, "Clicked position " + position + "!", Toast.LENGTH_SHORT).show();
  }

//第二种形式:参数有四个
    @OnItemClick(R.id.example_list) void onItemClick(AdapterView mView,View itemView,int position,long num) {
        Toast.makeText(this, "Clicked position " + position + "!", Toast.LENGTH_SHORT).show();
  }

@ OnItemLongClick
这个注解主要是针对AdapterView,即类似ListView这样的控件使用的事件类型,貌似在实际RecycleView不是继承与AdapterView,因此不能使用此注解

//第一种形式:参数只有一个position
    @ OnItemLongClick (R.id.example_list) void onItemClick(int position) {
        Toast.makeText(this, "Clicked position " + position + "!", Toast.LENGTH_SHORT).show();
  }

//第二种形式:参数有四个
    @OnItemLongClick(R.id.example_list) 
void onItemClick(AdapterView mView,View itemView,int position,long num) {
        Toast.makeText(this, "Clicked position " + position + "!", Toast.LENGTH_SHORT).show();
  }

@ OnItemSelected
针对的控件也是AdapterView的子类,即ListView以及Spinner这一类,这个注释的使用与OnItemSelectedListener的使用方式类似

@OnItemSelected(R.id.example_list) void onItemSelected(int position) {
            Toast.makeText(this, "Selected position " + position + "!", Toast.LENGTH_SHORT).show();
    }


@OnItemSelected(R.id.example_list) void onItemSelected(android.widget.AdapterView view, android.view.View mview, int position, long id) {
            Toast.makeText(this, "Selected position " + position + "!", Toast.LENGTH_SHORT).show();
    }


@OnItemSelected(value = R.id.example_list, callback = NOTHING_SELECTED)
    void onNothingSelected() {
        Toast.makeText(this, "Nothing selected!", Toast.LENGTH_SHORT).show();
    }

@ OnLongClick
OnLongClick很简单,其实也就是点击事件,只是在ButterKnife中点击事件中的参数可以没有,也可以有一个View类型,,没有绑定View,也可以生效

@OnLongClick (R.id.example) 
    void onClick() {
        Toast.makeText(this, " OnLongClick!", Toast.LENGTH_SHORT).show();
    }

@OnLongClick ({R.id.topText,R.id.bottom_text})
    void onTextViewClick(View mView){
        Toast.makeText(BufferKnifeDemoActicity.this,((TextView)mView).getText().toString(),Toast.LENGTH_LONG).show();
}

@ OnPageChange
OnPageChange注解主要是针对ViewPager来进行实现的,ViewPager中有OnPageChangeListener啊


//使用方式一:
OnPageChange(R.id.example_pager) void onPageSelected(int position) {
  Toast.makeText(this, "Selected " + position + "!", Toast.LENGTH_SHORT).show();
}

//使用方式二:
@OnPageChange(value = R.id.example_pager, callback = PAGE_SCROLL_STATE_CHANGED)
void onPageStateChanged(int state) {
    Toast.makeText(this, "State changed: " + state + "!", Toast.LENGTH_SHORT).show();
}

//使用方式三:
@OnPageChange(value = R.id.example_pager, callback = PAGE_SCROLLED)
void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {

}
//主要是通过枚举类型,PAGE_SCROLLED,PAGE_SCROLL_STATE_CHANGED,PAGE_SELECTED来进行判断使用的

@ OnTextChanged
主要是针对TextWatcher控件来进行实现的。

//使用方式一:
@OnTextChanged(R.id.example) void onTextChanged(CharSequence text) {
    Toast.makeText(this, "Text changed: " + text, Toast.LENGTH_SHORT).show();
}

//使用方式二:
@OnTextChanged(value = R.id.example, callback = BEFORE_TEXT_CHANGED)
void onBeforeTextChanged(CharSequence text) {
   Toast.makeText(this, "Before text changed: " + text, Toast.LENGTH_SHORT).show();
 }

//使用方式三:
@OnTextChanged(value = R.id.example, callback = AFTER_TEXT_CHANGED )
void onAfterTextChange(Editable editable) {
   Toast.makeText(this, "after text changed: " + text, Toast.LENGTH_SHORT).show();
 }
//与OnPagerChange使用类似,其也是用过枚举变量来进行控制的,BEFORE_TEXT_CHANGED,TEXT_CHANGED,AFTER_TEXT_CHANGED

@ OnTouch
针对所有的View都有的onTouch事件来进行设计的,只要是View的子类都可以使用此注解

//使用方式一:
    @OnTouch(R.id.example) boolean onTouch() {
            Toast.makeText(this, "Touched!", Toast.LENGTH_SHORT).show();
            return false;
    }
//使用方式二,带参数类型
    @OnTouch(R.id.example) boolean onTouch(View mView,MotionEvent event) {
            Toast.makeText(this, "Touched!", Toast.LENGTH_SHORT).show();
            return false;
    }
//注意点:
    //OnTouch为了与系统的onTouch进行匹配上,即满足事件传递的要求,所以其是有返回值的,也就要求没和函数都是要有返回值。

@ Optional
默认情况下,@Bind 和listener的注入都是必须的,如果target view没有被发现,则会报错. 为了抑制这种行为,可以用@Optional注解来标记field和方法,让注入变成选择性的,如果targetView存在,则注入, 不存在,则什么事情都不做.或者使用 Android’s “support-annotations” library.中的@Nullable来修饰

@Optional @OnClick(R.id.subtitle) void onSubtitleClick() {}
ButterKnife的findById

ButterKnife 也提供了findById函数,通过findById()可以获取Activity、Dialog、View中的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);
不过以上的一个方法其实已经过时了,官方其实不再建议去使用这几个方法了

ButterKnife.apply()函数
函数类型:

在ButterKnife这个类中关于apply方法的重载数量高达到12条,由此可以看出来,apply这个函数的重要性。但是这个函数使用来干嘛的撒???
ButterKnife中的apply()函数对view集合元素或者单个view的Action, Setter和Property进行修改。
要想知道的方式,必须首先看一下它的函数类型参数类型吧:如以下所示:

@UiThread @SafeVarargs 
1:public static <T extends View> void apply(@NonNull List<T> list, @NonNull Action<? super T>... actions)

@UiThread @SafeVarargs 
2:public static <T extends View> void apply(@NonNull T[] array, @NonNull Action<? super T>... actions)

@UiThread
3:public static <T extends View> void apply(@NonNull List<T> list,@NonNull Action<? super T> action)

@UiThread
4:public static <T extends View> void apply(@NonNull T[] array, @NonNull Action<? super T> action)

@UiThread
5:public static <T extends View> void apply(@NonNull List<T> list,@NonNull Action<? super T> action)

6:
@UiThread @SafeVarargs 
public static <T extends View> void apply(@NonNull T view,@NonNull Action<? super T>... actions)

7:
@UiThread
public static <T extends View> void apply(@NonNull T view, @NonNull Action<? super T> action)

8: 
@UiThread
public static <T extends View, V> void apply(@NonNull List<T> list,@NonNull Setter<? super T, V> setter, V value)

9:
@UiThread
public static <T extends View, V> void apply(@NonNull T[] array,@NonNull Setter<? super T, V> setter, V value)

10: 
@UiThread
public static <T extends View, V> void apply(@NonNull T view,@NonNull Setter<? super T, V> setter, V value)

11: 
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) // http://b.android.com/213630
@RequiresApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@UiThread
public static <T extends View, V> void apply(@NonNull List<T> list,@NonNull Property<? super T, V> setter, V value)

12     
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) // http://b.android.com/213630
@RequiresApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@UiThread
public static <T extends View, V> void apply(@NonNull T[] array,@NonNull Property<? super T, V> setter, V value)
参数解释:

所有的函数其实都围绕三个参数类型来的:

1:泛型类型为View子类的类型或者泛型数组或者泛型集合,可以参数可以认为是绑定的View类型
2:Action类型的接口和Setter类型的接口

public interface Action<T extends View> {
    /** Apply the action on the {@code view} which is at {@code index} in the list.*/
        @UiThread
        void apply(@NonNull T view, int index);
  }

/** A setter that can apply a value to a list of views. */
public interface Setter<T extends View, V> {
    /** Set the {@code value} on the {@code view} which is at {@code index} in the list. */
    @UiThread
     void set(@NonNull T view, V value, int index);
  }

其实Action接口主要是为了对View或者Views进行管理操作,而Setter接口其实就是对view或者views的属性或者值进行操作管理

使用案例:
使用方式一:
//1:绑定View
  @Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })  
  List<EditText> nameViews; 

//2:定义Action或者Setter的实现接口类型
  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);  
  }  
};

//3:对views调用apply,修改views中每个view类型属性
ButterKnife.apply(nameViews, DISABLE);  
ButterKnife.apply(nameViews, ENABLED, false);

使用方式二:
    对于系统的相关属性可以直接系统默认的属性常量进行设置
    ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
代码混淆方式
-keep class butterknife.** { *; }  
-dontwarn butterknife.internal.**  
-keep class **$$ViewBinder { *; }  

-keepclasseswithmembernames class * {  
    @butterknife.* <fields>;  
}  

-keepclasseswithmembernames class * {  
    @butterknife.* <methods>;  
} 

以上就是关于
ButterKnife的使用,如果对你的学习有帮助的话,点个关注撒。后续从源码角度分析这种绑定的机制

欢迎持续访问博客:https://blog.csdn.net/qq_29924041

  • 11
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android Studio的ButterKnife是一个用于简化Android开发视图绑定的开源。它可以帮助开发者通过注解方式快速地绑定视图资源,减少findViewById的使用,提高开发效率。 使用ButterKnife,首先需要在项目的build.gradle文件添加依赖: ```groovy dependencies { implementation 'com.jakewharton:butterknife:10.2.1' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1' } ``` 然后,在需要使用ButterKnife的Activity或Fragment使用`@BindView`注解来绑定视图资源。 例如,在Activity绑定一个TextView: ```java public class MainActivity extends AppCompatActivity { @BindView(R.id.textView) TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); // 视图绑定 // 使用textView textView.setText("Hello ButterKnife!"); } } ``` 在Fragment使用类似的方式绑定视图资源。 需要注意的是,使用ButterKnife进行视图绑定时,必须在`setContentView()`之后调用`ButterKnife.bind(this)`来完成绑定。 除了`@BindView`注解外,ButterKnife还提供了其他注解,如`@OnClick`用于点击事件的绑定、`@Nullable`用于可为空的注解等。 值得一提的是,自从Android Studio 3.6版本起,Google推出了ViewBinding功能,它提供了类似ButterKnife的视图绑定功能,并且是官方支持的。如果使用最新版本的Android Studio,建议使用ViewBinding来代替ButterKnife

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值