DataBinding 与 mvvm 模式(二)其他类型数据绑定

版权声明:转载请说明出处:http://blog.csdn.net/yhaolpz https://blog.csdn.net/yhaolpz/article/details/68066472

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 ~

猜你喜欢

转载自blog.csdn.net/yhaolpz/article/details/68066472