DataBinding 系列文章:
DataBinding 与 mvvm 模式(一)文本类型数据绑定
DataBinding 与 mvvm 模式(二)其他类型数据绑定
首先我们回顾一下在程序中使用 DataBinding 的步骤:
1. 启用 DataBinding
2. 创建 viewModel
3. 创建 layout 布局
4. 建立绑定关系
OK~ ,上篇介绍的是最简单的文本类型数据绑定,这里的类型指的是控件需要的数据类型,比如 android:text 需要的就是文本类型数据,所以在 viewModel 中直接设置对应的 String 类型属性就可以了。如果我们要对控件绑定的数据是其他类型的,比如 android:textColor 、android:src ,这时该怎么实现呢? 有以下两种方法:
1. getXxx 方法返回控件需要的数据类型
2. 使用 @BindingAdapter 注解
下面分别通过这两种方法实现以下效果:
假如我们的 viewModel 中表示颜色的数据是 boolean 类型的:
private boolean isRed;
layout 文件:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="person"
type="com.yhao.test.Person"/>
</data>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{person.name}"
android:textColor="@{person.isRed}"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="click"
android:text="change red"
/>
</LinearLayout>
</layout>
在程序中只需改变 data :
public class MainActivity extends AppCompatActivity {
Person person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
person = new Person();
person.setName("yhao");
binding.setPerson(person);
}
public void click(View view) {
person.setRed(true);
}
}
通过第一种方法: getXxx 方法返回控件需要的数据类型实现,应该是这样的:
public class Person extends BaseObservable {
private String name;
private boolean isRed;
@Bindable
public int getIsRed() {
return isRed ? 0xFFFF0000 : 0xFF000000;
}
public void setRed(boolean red) {
isRed = red;
notifyPropertyChanged(BR.isRed);
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
通过第二种方法:使用 @BindingAdapter 注解实现,则应该是这样的:
public class Person extends BaseObservable {
private String name;
private boolean isRed;
@Bindable
public boolean getIsRed() {
return isRed;
}
public void setRed(boolean red) {
isRed = red;
notifyPropertyChanged(BR.isRed);
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@BindingAdapter("android:textColor")
public static void setRedColor(TextView textView, boolean isRed) {
if (isRed) {
textView.setTextColor(Color.RED);
}
}
}
其中 @BindingAdapter(“android:textColor”) 表示控件的 android:textColor 属性通过此方法来赋值,不直接通过 getXxx 方法赋值,另外此方法必须用 static 修饰,方法名可以是任意的,参数为控件和 getXxx 得到的 data,
其中 @BindingAdapter 不只可以作用于 android:textColor 等已存在的属性,也可以自定义一个属性,如
@BindingAdapter("app:color")
public static void setRedColor(TextView textView, boolean isRed) {
if (isRed) {
textView.setTextColor(Color.RED);
}
}
此时 layout 中控件使用该自定义属性即可:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{person.name}"
app:color="@{person.isRed}"
/>
如果我们要对 ImageView 绑定图片数据该怎么做呢?如下:
假如我们的 viewModel 中有一个图片资源 Id 需要与 ImageView 绑定, layout 文件中是这样的:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="person"
type="com.yhao.test.Person"/>
</data>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@{person.imgResId}"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="click"
android:text="change img"
/>
</LinearLayout>
</layout>
程序中只需要改变 data :
public class MainActivity extends AppCompatActivity {
private int[] imgsId = new int[]{R.mipmap.ic_launcher, R.drawable.star_r};
Person person;
private boolean flag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
person = new Person();
person.setImgResId(imgsId[0]);
binding.setPerson(person);
}
public void click(View view) {
if (flag) {
person.setImgResId(imgsId[0]);
} else {
person.setImgResId(imgsId[1]);
}
flag = !flag;
}
}
viewModel 中通过 @BindingAdapter 注解实现:
public class Person extends BaseObservable {
private int imgResId;
@Bindable
public int getImgResId() {
return imgResId;
}
public void setImgResId(int imgResId) {
this.imgResId = imgResId;
notifyPropertyChanged(BR.imgResId);
}
@BindingAdapter("android:src")
public static void setImg(ImageView textView, int imgResId) {
textView.setImageResource(imgResId);
}
}
此案例也可以通过改造 getImgResId 方法实现,但除了文本数据类型之外,推荐使用 @BindingAdapter 注解方法,因为前者的使用情景是有局限性且实现较为复杂的,毕竟我们要在方法中实现数据的类型转换。而 @BindingAdapter 注解方法就十分灵活易用,因为在 @BindingAdapter 注解方法中我们可以拿到控件,可以方便的对控件进行各种各样的操作。
上面介绍了颜色和本地图片数据的绑定,下面介绍一下从网络加载的图片数据绑定实现,如下:
layout 文件如下:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="person"
type="com.yhao.test.Person"/>
</data>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@{person.imgUrl}"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="click"
android:text="load img"
/>
</LinearLayout>
</layout>
程序中只需要改变 data :
public class MainActivity extends AppCompatActivity {
private String imgUrl = "http://avatar.csdn.net/7/7/0/1_yhaolpz.jpg";
Person person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
person = new Person();
binding.setPerson(person);
}
public void click(View view) {
person.setImgUrl(imgUrl);
}
}
viewModel 中结合 Glide 框架可以非常方便的实现图片加载, 记住要添加访问网络权限:
public class Person extends BaseObservable {
private String imgUrl;
@Bindable
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
notifyPropertyChanged(BR.imgUrl);
}
@BindingAdapter("android:src")
public static void setImg(ImageView imageView, String imgUrl) {
Glide.with(imageView.getContext())
.load(imgUrl)
.into(imageView);
}
}
怎么样,是不是非常简单?最后我们来总结一下:
本文介绍绑定颜色数据、绑定本地图片资源以及绑定网络图片三个案例,对于除了文本类型数据之外的其他类型数据,我们可以通过改造 getXxx 和 @BindingAdapter 注解两种方法实现绑定,推荐使用 @BindingAdapter 注解方式,因为它更加灵活易用。当然实际开发中会涉及到 ListView 、GridView 等复杂控件,下篇文章将介绍这些复杂控件如何实现 DataBinding ~