android:DataBinding使用小结(一)

一、初步使用DataBinding

  • 引入DataBinding

    在你的app下的build.gradle中添加对DataBinding的支持
    
android {
    ...
    //第一步:引入dataBinding
    dataBinding {
        enabled = true
    }

}
  • 更改你的xml布局,对dataBinding的支持
<?xml version="1.0" encoding="utf-8"?>
<!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tsou.cn.databinding.MainActivity">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Last Name" />

        <TextView
            android:id="@+id/first_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/last_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</layout>

  • 在MainActivity中使用dataBinding绑定你的xml布局,并代替findviewbyid

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        User user = new User();
        user.setFristName("huang");
        user.setLastName("xiaoguo");
        //    第三步:使用  ActivityMainBinding
        /**
         * Android studio会根据layout文件自动生成一个默认的Binding类,
         * 类名是根据layout文件名生成的,
         * 并有"Binding"后缀结束。
         * 例如:activity_main.xml生成的Binding类为ActivityMainBinding
         *
         * 如果ActivityMainBinding,无法找到,可以先编译一下项目
         */
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        /**
         * 解决问题之:findviewbyId
         */
        binding.firstName.setText(user.getFristName());
        binding.lastName.setText(user.getLastName());

    }

二、DataBinding 绑定UI (setVariable、setXXX)

  • 在xml中添加data数据绑定标签
<?xml version="1.0" encoding="utf-8"?>
<!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!--
    第四步:xml数据绑定,name表示数据对象名称
    type:表示包名
    -->
    <data>
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User"/>
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tsou.cn.databinding.MainActivity">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Last Name" />

        <TextView
            android:text="@{user.fristName}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:text="@{user.lastName}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</layout>

  • 将activity中的数据绑定到xml中

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        User user = new User();
        user.setFristName("huang");
        user.setLastName("xiaoguo");
        //    第三步:使用  ActivityMainBinding
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        /**
         * 将数据绑定到xml
         */
        //  方法一:(常用)
        //binding.setUser(user);
        //方法二:
        binding.setVariable(BR.user,user);

    }
}
  • 其他引入数据姿势

    如果用户类型要多处用到,也可以直接将之后导入进来,
    这样就不用每次都指明整个包名路径了,
    而java.lang.*包中的类会被自动导入,所以可以直接使用
    
<data>
        <import type="tsou.cn.databinding.bean.User"/>
        <variable
            name="user"
            type="User"/>
    </data>
如果存在进口的类名相同的情况,可以使用别名指定别名
<data>
        <import type="tsou.cn.databinding.bean.User" />
        <import
            alias="TwoUser"
            type="tsou.cn.databinding.bean2.User" />
        <variable
            name="user"
            type="User" />
        <variable
            name="twoser"
            type="TwoUser" />
    </data>

三、事件绑定

  • 创建Presenter类
 public class Presenter{
        //普通方法绑定
        public void onTextChanged( CharSequence s,int start,int before,int color){
            user.setFristName(s.toString());
            binding.setUser(user);
        }
        //普通方法绑定
        public void onClick(View view){
            Toast.makeText(MainActivity.this.getApplicationContext(),"点击了",Toast.LENGTH_LONG).show();
        }
        //监听器绑定,可以返回数据
        public void onClickListenerBinding(User user){
            Toast.makeText(MainActivity.this.getApplicationContext(),user.getLastName(),Toast.LENGTH_LONG).show();
        }
    }
  • 在xml中传入presenter并进行绑定
<?xml version="1.0" encoding="utf-8"?><!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--
        第四步:xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
        <!--
          第五步:事件绑定
          name:类名
          type:表示包名
        -->
        <variable
            name="presenter"
            type="tsou.cn.databinding.MainActivity.Presenter" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tsou.cn.databinding.MainActivity">
        <!--
          建议使用
         android:onTextChanged="@{presenter::onTextChanged}"
         可以将方法的绑定和普通函数的调用或数据绑定,区分开
        -->
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name"
            android:onTextChanged="@{presenter.onTextChanged}" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Last Name" />

         <!--
         普通方法绑定
          建议使用
          android:onClick="@{presenter::onClick}"
         可以将方法的绑定和普通函数的调用或数据绑定,区分开
        -->
        <TextView
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{presenter.onClick}"
            android:text="@{user.fristName}" />
        <!--
            监听器绑定,可以返回数据
        -->
        <TextView
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->presenter.onClickListenerBinding(user)}"
            android:text="@{user.lastName}" />
    </LinearLayout>
</layout>

  • acticity中绑定Presenter对象
binding.setPresenter(new Presenter());
  • 效果如下:

这里写图片描述

四、xml中对表达式的支持

支持的运算符:

  • 数学运算符: + - / * %
  • 字符串拼接: +
  • 逻辑运算符: && ||
  • 二进制: & | ^
  • 一元运算符: +
  • 位运算符: >> >>> <<
  • 比较: == > < >= <=
  • instanceof
  • ()
  • 数据类型: character, String, numeric, null
  • 类型转换(ClassCast)
  • 方法回调(Method calls)
  • 数据属性
  • 数组:[]
  • 三元操作符:?

例如:

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:background="@{true ? @color/colorAccent : @color/colorPrimary}"        
android:transitionName='@{"image_" + id}'

一些在java中常用而DataBinding xml中不支持的:

  • this
  • super
  • new
  • 泛型

空合并运算符

android:text="@{user.displayName ?? user.lastName}"

等价于

android:text="@{user.displayName != null ? user.displayName : user.lastName}"
  • view的显示和隐藏

在xml data节点下引入view

<data>

        <import type="android.view.View" />

    </data>

view的显示和隐藏

 <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="是否显示"
            android:textColor="@color/colorAccent"
            android:textSize="24sp"
            android:visibility="@{user.isShow ? View.VISIBLE:View.GONE }" />

五、include的使用

  • 创建include布局
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <!--
        xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{user.fristName}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{user.lastName}" />

    </LinearLayout>
</layout>

  • 使用include布局并传递数据
<include
         layout="@layout/include_layout"
         bind:user="@{user}" />
  • 效果如下
    这里写图片描述

六、ViewStub使用

  • ViewStub布局
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <!--
        xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:src="@mipmap/ic_launcher_round" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.imageId}" />
    </LinearLayout>
</layout>
  • 调用ViewStub
 <ViewStub
            android:id="@+id/view_stub"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout="@layout/viewstub"
            bind:user="@{user}" />
  • 加载viewStub
 //使用viewStub
   binding.viewStub.getViewStub().inflate();

七、BaseObservable数据更新监听使用

  • 将javaBean继承BaseObservable
package tsou.cn.databinding.bean;

import android.databinding.BaseObservable;
import android.databinding.Bindable;

import tsou.cn.databinding.BR;


/**
 * Created by Administrator on 2018/5/25 0025.
 */

//BaseObservable数据自动更新的使用

public class User extends BaseObservable {
    private String fristName;
    private String lastName;
    private String imageUrl;
    private boolean isShow;

    @Bindable
    public boolean getIsShow() {
        return isShow;
    }

    public void setIsShow(boolean show) {
        isShow = show;
        notifyPropertyChanged(BR.isShow);
    }

    @Bindable
    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
        notifyPropertyChanged(BR.imageUrl);
    }

    @Bindable
    public String getFristName() {
        return fristName;
    }

    public void setFristName(String fristName) {
        this.fristName = fristName;
        notifyPropertyChanged(BR.fristName);
    }

    @Bindable
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}
注意:
1、首先当前类继承BaseObservable 

2、对于get方法添加@Bindable注解

3、引入BR.lastName等报错时,需要对项目先进行一下修复
  • 布局中进行监听
<EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="输入 Frist Name"
            android:onTextChanged="@{presenter::onTextChanged}" />
  • 调用方法
 public class Presenter {
        //普通方法绑定
        public void onTextChanged(CharSequence s, int start, int before, int color) {
            user.setFristName(s.toString());
            //此时不需要再次手动进行更新数据对象了
//            binding.setUser(user);
        }
    }

八、ObservableField数据监听的使用

ObservableField是为了解决一个数据类中不需要所有的数据都进行监听时代替BaseObservable,让类当前类不需要继承BaseObservable也不需要重新notifyPropertyChanged方法
  • 在数据类中
    /**
     * 在单个或者比较少的数据需要监听时使用ObservableField
     * (ObservableBoolean,ObservableChar,ObservableInt,ObservableParcelable.....)
     */
    private ObservableField<Boolean> isShow = new ObservableField<>();

    public ObservableField<Boolean> getIsShow() {
        return isShow;
    }

    public void setIsShow(boolean show) {
        /**
         * 如果是Observable*类型设置数据需要使用set
         */
        this.isShow.set(show);
    }
  • 布局中使用
<TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="是否显示"
            android:textColor="@color/colorAccent"
            android:textSize="24sp"
            android:visibility="@{user.isShow ? View.VISIBLE:View.GONE }" />
  • 更新数据
 public class Presenter {
        //普通方法绑定
        public void onTextChanged(CharSequence s, int start, int before, int color) {
            user.setFristName(s.toString());
            //这里直接更改数据就好
            user.setIsShow(!user.getIsShow().get());
//            binding.setUser(user);
        } 
    }

九、ObservableArrayList和ObservableArrayMap的使用

  • 在数据类中
  private ObservableArrayList<String> nums;
    private ObservableArrayMap<String,String> maps;
    public ObservableArrayList<String> getNums() {
        return nums;
    }
    public void setNums(ObservableArrayList<String> nums) {
        this.nums=nums;
    }

    public ObservableArrayMap<String, String> getMaps() {
        return maps;
    }

    public void setMaps(ObservableArrayMap<String, String> maps) {
        this.maps = maps;
    }
  • 布局中使用
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{user.nums[0]}" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text='@{user.maps["name"]}' />
  • 添加数据

全局集合对象

private ObservableArrayList<String> nums = new ObservableArrayList<>();
    private ObservableArrayMap<String, String> maps = new ObservableArrayMap<>();

在绑定数据之前添加集合对象

 //ObservableArrayList和ObservableArrayMap的使用:添加对象
        user.setNums(nums);
        user.setMaps(maps);

        /**
         * 将数据绑定到xml
         */
        //  方法一:
        //binding.setUser(user);
        //方法二:
        binding.setVariable(BR.user, user);

更改数据

  nums.add("我是ObservableArrayList");
  maps.put("name", "我是ObservableArrayMap");

十、BindingAdapter的使用

  • 使用BindingAdapter构建图片加载方法

/**
 * Created by Administrator on 2018/5/30 0030.
 */

public class ImageUtil {
    @BindingAdapter({"url"})
    public static void loadImage(ImageView view, String url) {

        Glide.with(UIUtils.getContext()).load(url).into(view);
    }
}
  • xml文件绑定数据
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>
        <!--
        xml数据绑定,name表示数据对象名称
        type:表示包名
         -->
        <variable
            name="user"
            type="tsou.cn.databinding.bean.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!--
        这里的bind:url="@{user.imageUrl}"即为调用 @BindingAdapter({"url"}绑定的数据
        -->
        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            bind:url="@{user.imageUrl}"
            android:src="@mipmap/ic_launcher_round" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.imageUrl}" />
    </LinearLayout>
</layout>

  • 添加Url数据
user.setImageUrl("https://unsplash.it/200/200?random&10");

  • BindingAdapter更加强大的一点是可以覆盖Android原先的控件属性。例如,可以设定每一个TextView的文本都要加上后缀:“ - 追加的数据”

    注意:这里追加数据的TextView必须使用数据绑定来填充数据,否则无效
    
 @BindingAdapter("android:text")
    public static void setText(TextView view, String text) {
        view.setText(text + "-追加的数据");
    }

这里写图片描述

十一、BindingConversion使用

dataBinding还支持数据进行转换,或者进行类型转换。

与BindingAdapter类似,以下方法会将布局文件中所有以@{String}方式引用到的String类型变量加上后缀-conversionString

    @BindingConversion
    public static String conversionString(String text) {
        return text + "-conversionString";
    }
<TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{"xxx"}'
            android:textAllCaps="false"/>

这里写图片描述

可以看到,对于TextView来说,BindingAdapter和BindingConversion同时生效了,而BindingConversion的优先级要高些。此外,BindingConversion也可以用于转换属性值的类型。

看以下布局,此处在向background和textColor两个属性赋值时,直接就使用了字符串,按正常情况来说这自然是会报错的,但有了BindingConversion后就可以自动将字符串类型的值转为的需要Drawable状语从句:Color了

<TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background='@{"红色"}'
            android:padding="20dp"
            android:text="红色背景蓝色字"
            android:textColor='@{"蓝色"}'/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:background='@{"蓝色"}'
            android:padding="20dp"
            android:text="蓝色背景红色字"
            android:textColor='@{"红色"}'/>
@BindingConversion
    public static Drawable convertStringToDrawable(String str) {
        if (str.equals("红色")) {
            return new ColorDrawable(Color.parseColor("#FF4081"));
        }
        if (str.equals("蓝色")) {
            return new ColorDrawable(Color.parseColor("#3F51B5"));
        }
        return new ColorDrawable(Color.parseColor("#344567"));
    }

    @BindingConversion
    public static int convertStringToColor(String str) {
        if (str.equals("红色")) {
            return Color.parseColor("#FF4081");
        }
        if (str.equals("蓝色")) {
            return Color.parseColor("#3F51B5");
        }
        return Color.parseColor("#344567");
    }

这里写图片描述

十二、Array、List、Set、Map …

dataBinding也支持在布局文件中使用数组,Lsit,Set和Map,且在布局文件中都可以通过list[index]形式来获取元素。

而为了和变量标签的尖括号区分开,在声明Lsit 之类的数据类型时,需要使用尖括号的转义字符。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="java.util.List" />
        <import type="java.util.Map" />
        <import type="java.util.Set" />
        <import type="android.util.SparseArray" />
        <variable
            name="array"
            type="String[]" />
        <variable
            name="list"
            type="List&lt;String&gt;" />
        <variable
            name="map"
            type="Map&lt;String, String&gt;" />
        <variable
            name="set"
            type="Set&lt;String&gt;" />
        <variable
            name="sparse"
            type="SparseArray&lt;String&gt;" />
        <variable
            name="index"
            type="int" />
        <variable
            name="key"
            type="String" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".Main7Activity">

        <TextView
            ···
            android:text="@{array[1]}" />
        <TextView
            ···
            android:text="@{sparse[index]}" />
        <TextView
            ···
            android:text="@{list[index]}" />
        <TextView
            ···
            android:text="@{map[key]}" />
        <TextView
            ···
            android:text='@{map["leavesC"]}' />
        <TextView
            ···
            android:text='@{set.contains("xxx")?"xxx":key}' />
    </LinearLayout>
</layout>

十三、资源引用

dataBinding支持对尺寸和字符串这类资源的访问

  • dimens.xml
  <dimen name="paddingBig">190dp</dimen>
    <dimen name="paddingSmall">150dp</dimen>
  • strings.xml
  <string name="format">%s is %s</string>
  <data>
        <variable
            name="flag"
            type="boolean" />
    </data>       
    <Button
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingLeft="@{flag ? @dimen/paddingBig:@dimen/paddingSmall}"
         android:text='@{@string/format("leavesC", "Ye")}'
         android:textAllCaps="false" />

其他注意知识点

  • 默认数据

    由于@{userInfo.name}在布局文件中并没有明确的值,
    所以在预览视图中什么都不会显示,
    不便于观察文本的大小和字体颜色等属性,
    此时可以为之设定默认值(文本内容或者是字体大小等属性都适用),
    默认值将只在预览视图中显示,且默认值不能包含引号

android:text="@{user.fristName,default=这是默认数据}"
  • 自定义实例名称

    每个数据绑定布局文件都会生成一个绑定类,
    ViewDataBinding的实例名是根据布局文件名来生成,
    将之改为首字母大写的驼峰命名法来命名,
    并省略布局文件名包含的下划线。
    控件的获取方式类似,但首字母小写。
    也可以通过如下方式自定义ViewDataBinding的实例名
    
<data class="CustomBinding">

</data>

Demo地址:https://download.csdn.net/download/huangxiaoguo1/10454497

猜你喜欢

转载自blog.csdn.net/huangxiaoguo1/article/details/80453530