内容简介:看了谷歌官方文章确实写的太简略了,甚至看完之后有很多地方还不知道怎么回事儿或者怎么用,那么接下来我将通过几篇文章全面介绍一下 DataBinding 以及 DataBinding 的使用。我们通过两篇文章,分别介绍了 DataBinding() ,以及 DataBinding 的简单使用(
看了谷歌官方文章确实写的太简略了,甚至看完之后有很多地方还不知道怎么回事儿或者怎么用,那么接下来我将通过几篇文章全面介绍一下 DataBinding 以及 DataBinding 的使用。
GitHub传送门 欢迎Star 下载
如有任何问题 关注 “朝阳杨少爷” 公众号给我留言,我会及时回复。
写在前面
我们通过两篇文章,分别介绍了 DataBinding( Android Jetpack系列——细说DataBinding
) ,以及 DataBinding 的简单使用( DataBinding 的简单使用
) ,这篇文章,我们来介绍一下 DataBinding 最佳实践——Binding adapters
我之所以说 Binding adapters 是 DataBinding 的最佳实践,是因为用过了才知道是真的好用!
下面我们就通过这篇文章全面的介绍一下 Binding adapters。
请耐心看完这篇文章,就知道真的好用!
DataBinding里的注解方法讲解
在正式介绍 Binding adapters 之前,我们先了解一下 DataBinding 里的注解方法。
@Bindable
用于数据更新自动刷新视图。
@BindingAdapter
这个注解用于支持自定义属性,或者是修改原有属性。注解值可以是已有的 xml 属性,例如 android:src、android:text等,也可以自定义属性然后在 xml 中使用。
列如官方示列当中,就介绍了个 「setPadding」 的例子。
@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, padding: Int) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom())
}
复制代码
接受多个属性的适配器。
@BindingAdapter(value = { "imageUrl", "error" }, requireAll = false)
fun loadImage(view: ImageView, url: String, error: Drawable) {
Picasso.get().load(url).error(error).into(view)
}
复制代码
从上面,我们可以注意到几个关键的地方:
- 修饰的方法,必须是 public static
- 方法参数第一个要求必须是 View
- 方法名可以随意
- 最后一个 booblean 类型是可选参数。可以要求是否所有参数都需要填写,默认是true。
- 如果这里requireAll为false, 你没有填写的属性值将为null. 所以需要做非空判断。
这里需要特殊说明的是:
当发生冲突时,定义的绑定适配器将覆盖Android框架提供的默认适配器。
@BindingMethods
DataBinding默认可以在布局中使用setter方法作为自定义属性,
但是如果不是setter格式的方法就要使用BindingMethod注解了. 通过创建一个自定义属性来关联一个类中已有的方法。
该注解属于一个容器. 内部参数是一个@BindingMethod数组, 只能用于修饰类(任意类都可以, 类可以为空).
下面我们看一看官方示例:
@BindingMethods(value = [
BindingMethod(
type = android.widget.ImageView::class,
attribute = "android:tint",
method = "setImageTintList")])
复制代码
这里需要注意的是,这个注解必须有三个属性。
- type:字节码
- attribute:属性
- method:方法
会在指定的字节码(type)中寻找方法(method), 然后通过你创建的布局属性(Attribute)来回调方法。
如果属性名和@BindingAdapter冲突会报错
该注解只是单纯地关联已有的方法, 并不能新增方法. 所以全都是注解的空类.
@BindingConversion
属性值自动进行类型转换
列如,我们用的 android:background 属性是 Drawable 的,但是需要指定一个颜色值,而这个值是整数的。
那么我就需要用到了 @BindingConversion 注解。
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
复制代码
这里我们就可以用带有bindingConversion注释的静态方法进行转换,如下所示:
@BindingConversion fun convertColorToDrawable(color: Int) = ColorDrawable(color) 复制代码
但是,绑定表达式中提供的值类型必须一致。不能在同一表达式中使用不同的类型,列如如下的错误示范:
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
复制代码
通过,以上我们可以注意到:
- 只能修饰 public static 方法。
- 任意位置任意方法名都不被限制。
- DataBinding自动匹配被该注解修饰的方法和匹配参数类型。
- 返回值类型必须喝属性setter方法匹配,且参数只能有一个。
- 要求属性值必须是@{}DataBinding表达式。
Binding adapters的使用实践
通过上面的介绍,我们了解到了这几个注释方法,接下来,我们就要开始使用这些方法。
下面就开始实践使用:
@Bindable
这个注解的理解还是十分简单的。
使用 @Bindable 来标记的 get 方法,在编译时,会在BR类当中生成对应的字段,然后与 notifyPropertyChanged() 方法配合使用,当该字段中的数据被修改时,dataBinding 会自动刷新对应view的数据,而不用我们在拿到新数据后重新把数据在setText()一遍,就凭这一点,dataBinding就可以简化大量的代码。
以此来实现双向绑定,关于双向绑定的内容,我会通过下一篇文章来详细讲述,现在先简单介绍一下使用。
实体类也可以不用继承BaseObservable
,而是实现Observable接口,但是需要自行处理一些接口方法逻辑,BaseObservable是实现Observable接口的类,内部已经做好了相关逻辑处理,所以选择继承BaseObservable相对简单一些。
接下来我们看一下如何在代码里实现:
class StudentInfo : BaseObservable() {
@get:Bindable
var name: String? = null
@get:Bindable
var age: Int = 0
@get:Bindable
var sex: String? = null
@get:Bindable
var score: Int = 0
}
复制代码
这样,我们的实体类就完成了。具体的使用方法和效果,我们在之后讲解双向绑定的时候会着重介绍。
@BindingAdapter
这里我们必须着重介绍一下 BindingAdapter 这个注解。这个可能是我们在之后的使用当中,最常用的一个注解。
这个注解厉害了!
除了重新定义已经有的方法,还可以定义新的属性!
列如,我们有个View既没有android:xxx=""或者app:xxx=""属性,也没有setXxx()方法,我们通过@BindingAdapter同样可以实现自定义android:xxx=""或者app:xxx=""属性,然后使用!
除了定义属性职位,我们还可以定义一些不属于这个View的属性!
我们可以通过 @BindingAdapter 自定义一个或者一些属性,让我们可以在这个View当中,使用相应的属性!
例如我们定一个ImageView通过 @BindingAdapter 来定义一些属性。
@BindingAdapter(value = {"android:imageUrl", "android:placeHolder", "android:error"}, requireAll = false)
public static void loadImage(ImageView view, String url, Drawable error, Drawable placeHolder) {
Glide.with(view.getContext()).load(url).into(view);
}
复制代码
定义好之后,我们就可以开始使用了!
<ImageView
android:id="@+id/iv_binding_adapter"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:placeHolder="@{@drawable/ic_launcher"
android:imageUrl="@{url}"
android:error="@{@drawable/ic_launcher}"
/>
复制代码
值得注意的是,这里的 @drawable/ic_launcher,用@{}括住资源使其成为有效的绑定表达式。
但是,我有一点疑惑的是,现在我们图片的资源都放在mipmap系列文件夹下了,但是这里设置只能在drawable文件夹下面找到对应的资源?如果有什么想法和办法欢迎给我留言,我们交流一下!
还有一点注意的是,我们设置glide的时候,别忘了在AndroidManifest文件当中把权限设置上!
<uses-permission android:name="android.permission.INTERNET" /> 复制代码
接下来,我们就可以看到我们要实现的效果了
是不是很厉害!这样,我们可以节约多少代码!
以上只是一个简单的使用,还有更厉害的!
那就是配合RecyclerView设置adapter。RecyclerView可以说是我们最常用的一个控件,如果吧adapter和DataBinding结合之后,你会发现写Adapter会变得十分的简单!
更多的属性,都可以在xml当中完成。
setOnItemClickListener 、 setOnLoadMoreListener 、
等等这些我们常用的一些方法。列如,我们可以定义一个BindAdapter
public class RecyclerViewBindingAdapter {
@BindingAdapter(value = {"android:onItemClick", "android:onLoadMore",
"android:loadMoreEnable"}, requireAll = false)
public static void setupAdapter(RecyclerView recyclerView, final ItemClickListener itemClickListener,
final LoadMoreListener loadMoreListener, final boolean loadMoreEnable) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter == null || !(adapter instanceof BaseQuickAdapter)) {
return;
}
BaseQuickAdapter quickAdapter = (BaseQuickAdapter) adapter;
quickAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
itemClickListener.onItemClick(adapter, view, position);
}
});
quickAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
loadMoreListener.onLoadMore();
}
}, recyclerView);
quickAdapter.setEnableLoadMore(loadMoreEnable);
quickAdapter.setLoadMoreView(new RVLoadMoreView());
quickAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);
}
public interface ItemClickListener {
void onItemClick(BaseQuickAdapter adapter, View view, int position);
}
public interface LoadMoreListener {
void onLoadMore();
}
}
复制代码
在布局文件当中,使用我们刚才定义的属性
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:loadMoreEnable="@{true}"
android:onItemClick="@{presenter.onItemClick}"
android:onLoadMore="@{presenter.onLoadMore}"
app:adapter="@{adapter}"
app:layoutManager="LinearLayoutManager"/>
复制代码
通过上面的方式,我们就实现了通过在RecyclerView中配置属性达到为adapter设置点击监听,上拉加载监听,以及是否开启监听的目的。
这里值得注意的是:
其中的app:adapter="@{adapter}"是因为RecyclerView有setAdapter方法,结合databinding的特性,故而可以这样写。而app:layoutManager="LinearLayoutManager"属性是RecyclerView自己提供的一个属性,为了方便我们为RecyclerView设置layoutManager,其内部采用反射构造一个目标layoutManager,然后通过RecyclerView的public void setLayoutManager(LayoutManager layout)再进行设置。
最后
相信,通过上面的内容。已经能体会到了DataBinding的便捷之处。接下来,我们在讲讲双向绑定。如有任何问题,欢迎给我留言,我们一起讨论。
GitHub传送门 欢迎Star 下载
如有任何问题 关注 “朝阳杨少爷” 公众号给我留言,我会及时回复。
扫一扫,即刻加入到专属限免的星球当中,这里有很多有意思的人,好玩儿的事儿等你来耍!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- vue项目实践004~~~一篮子的实践技巧
- HBase实践 | 阿里云HBase数据安全实践
- Spark 实践:物化视图在 SparkSQL 中的实践
- Spark实践|物化视图在 SparkSQL 中的实践
- HBase实践 | 数据人看Feed流-架构实践
- Kafka从上手到实践-实践真知:搭建Zookeeper集群
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Design Accessible Web Sites
Jeremy Sydik / Pragmatic Bookshelf / 2007-11-05 / USD 34.95
It's not a one-browser web anymore. You need to reach audiences that use cell phones, PDAs, game consoles, or other "alternative" browsers, as well as users with disabilities. Legal requirements for a......一起来看看 《Design Accessible Web Sites》 这本书的介绍吧!