首页 > 学院 > 开发设计 > 正文

DataBinding实用型文档

2019-11-07 23:25:45
字体:
来源:转载
供稿:网友

官方文档

DataBinding 初尝试

配置 Model 的 build.gradle

android{ …… dataBinding { enabled true } ……}

修改布局文件

<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> …… </data> <!--原先的根节点(Root Element)--> 如: <LinearLayout android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> …… </LinearLayout></layout>

自定义用来配置展示数据的 POJO 类(java中一般叫JavaBean)(如果不需要更新数据,set方法不写也可以)

在布局文件添加data标签的参数

// 最基本的引用<data> <variable name="user" type="ll.withwings.testdatabinding.pojo.User" /></data>// 导入式引用<data> <import type="ll.withwings.testdatabinding.pojo.User" /> <variable name="user" type="User" /></data>

布局文件中使用

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

到了这一步会自动生成一个继承自 ViewDataBinding 的类。不生成就编译,再不生成就重启 AS。反正因为生成的文件在编译目录,所以我一直调不到后面用的方法,所以直接重启……

该类的名字是根据 布局文件的名字自动生成的

activity_main --> ActivityMainBinding

也可以自定义,需要再 data 标签设置

<data class="自定义名"> ……</data>

onCreate 方法,用 DatabindingUtil.setContentView() 来替换掉 setContentView()

ActivityMainBinding binding = DataBindingUtil.setContentView( this, R.layout.activity_basic);User user = new User("fei", "Liang");binding.setUser(user);

DataBinding 进阶

获得binding对象

Activity 的 onCreate 方法:替换setContentView

@Override PRotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); }

Fragment 的 onCreateView 中

// 第一种方法public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { FragmentTestBinding fragmentTestBinding = FragmentTestBinding.inflate(getActivity().getLayoutInflater()); fragmentTestBinding.setAa("3333333"); return fragmentTestBinding.getRoot();}// 第二种方法public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { MainActivityBinding binding = DataBindingUtil.inflate(inflater, R.layout.main_activity, container, false); return binding.getRoot();}

在 Adapter 的 item 中

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);//orListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

可以直接使用参数

java.lang.* 包中的类会被自动导入,可以直接使用,例如要定义一个 String 类型的变量:

<data> <variable name="firstName" type="String" /></data>

布局文件中使用

<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{firstName}" />

在 Activity 中设置内容

binding.setFirstName("");

使用方法设置展示内容

自定义一个类,使用静态有返回值的方法:(网上有说静态的方法,不过新版AS不支持静态的,所以别用)

// 如:public class MyStringUtils { public String capitalize(String Word) { if (word.length() > 1) { return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1); } return word; }}

在 data 标签中导入

<data> <variable name="StringUtils" type="ll.withwings.testdatabinding.utils.MyStringUtils" /></data>

在布局中调用

<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{StringUtils.capitalize(firstName)}" />

在代码中设置

binding.setFirstName("3");MyStringUtils stringUtils = new MyStringUtils();binding.setStringUtils(stringUtils);

注意:

不支持的表达式:thissupernewExplicit generic invocation

给导入的同名类起别名

data标签

空值合并运行符(Null Coalescing)

定义

$a = $b ?? $c

如果变量 b已经定义,没有被注销,并且不为null,就将b 的值赋给变量 a,否则将变量c 的值赋给变量 $a.

使用

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

三元运算符

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

属性值

android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"

资源引用

data标签中

<data> <variable name="large" type="boolean" /></data>

布局文件中

android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"

自定义属性值中

<dimen name="largePadding">20dp</dimen><dimen name="smallPadding">5dp</dimen>

代码中

binding.setLarge(true);

点击事件

data标签中

<data> <variable name="myClickListener" type="android.view.View.OnClickListener" /></data>

布局文件中

android:onClick="@{myClickListener}"

代码中

binding.setMyClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do something Toast.makeText(MainActivity.this, "333333", Toast.LENGTH_SHORT).show(); }});

根据id设置

布局文件中

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

代码中

binding.show.setText("Test");

Observable Binding

讲真,一开始我是在不理解绑定的意思,后来我终于发现,它的意思其实就是可以更该数据,之前数据更改。POJO类的修改,除非直接重新设置整个类,不然是不会自动更新数据的,这在ListView等多Item的情况下就会显得很不好用。

重定义 bean 类,继承自 BaSEObservable,在每个setter方法 中添加

notifyPropertyChanged(int fieldId);// 参数就是 BR.setter类的参数notifyPropertyChanged(BR.setter类名字);// 比如 setFirstName(String name){ mName = name;}// 此时:notifyPropertyChanged(BR.firstName);// 有没有很尴尬

比如

public class ObservableUser extends BaseObservable { private String firstName; private String lastName; @Bindable public String getFirstName() { return lastName; } @Bindable public String getLastName() { return lastName; } public void setFirstName(String firstName) { this.firstName = firstName; notifyPropertyChanged(BR.firstName); } public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR.lastName); }}

如果你发现你的全局变量跟setter方法的参数不同,很抱歉,两边都不遵守,请遵守set方法名的规范

如果你发现直接粘贴无法找到 BR 类,请不要担心,你可以手打一下BR,你会发现一件神奇的事情,BR 找到了。在 布局文件引用在 代码中设置展示的数据。

ViewStubs(include/ViewStub:引用布局)

主布局文件 使用 DataBinding 书写 如果没有需求,可以不写 data 标签子布局文件 使用 DataBinding 书写,data 链接需要展示的数据

代码实现

ActivityViewStubBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_view_stub);ViewStub viewStub = binding.viewStub.getViewStub();binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() { @Override public void onInflate(ViewStub stub, View inflated) { ViewStubBinding binding = DataBindingUtil.bind(inflated); User user = new User("fee", "lang"); binding.setUser(user); }});viewStub.inflate();

Dynamic Variables(ListView/RecyclerView)

RecyclerView 所在的布局文件不需要使用 DataBinding,这里主要针对 item 的动态展示

RecyclerView 对应的 bean 对象

public class User { private String name; private String age; public User(String name, String age) { this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public void setAge(String age) { this.age = age; } public String getName() { return this.name; } public String getAge() { return this.age; }}

item 布局文件 中 data 标签中

<data> <variable name="user" type="ll.withwings.testdatabinding.pojo.User"/></data>

item 布局文件 中 布局参数中

<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="@{user.name}"/><Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{user.age}"/>

代码设置中:

自定义 ViewHolder

添加常量 ViewDataBinding 对象给出 getter 和 setter 方法

自定义 Adapter

onCreateViewHolder 时获得 ViewDataBinding 和 ViewHolder

ItemRecyclerviewBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),R.layout.item_recyclerview,parent,false);MyViewHolder holder = new MyViewHolder(binding.getRoot());holder.setBinding(binding);return holder;

onBindViewHolder 方法中,set Bean 对象

User user = users.get(position);holder.getBinding().setVariable(BR.user,user);holder.getBinding().executePendingBindings();

Attribute setters

自定义属性:这个比较强大,不仅支持 自定义控件,即使官方控件也可以。用的好了,甚至可以代替自定义的 style

首先,自定义命名空间(万能命名空间 appNs 等待你的使用:AS输入appNs 自动生成)

xmlns:app="http://schemas.android.com/apk/res-auto"

使用自定义属性:需要知道,参数仅支持引用资源文件 @string/str 或者 data 标签定义的 DataBinding 引用来的参数。

app:myset="@{参数}"

资源文件

app:myset="@{@string/str}"

自定义

<app:myset="@{set}"

设置自定义属性功能:自定义方法,

添加注解

// 引号内就是我们自定义属性的名字@BindingAdapter("myset")

方法 静态 无返回值 参数使用 (自定义属性所在的标签对象,自定义属性的参数类型):位置方面说实话,我是没找到约束,我直接把他丢在一个类里面,他都能起效

比如我用的就是 TextView@BindingAdapter("myset")public static void setaaa(TextView textView, String url) { textView.setText(url);}

转换器 (Converters)

说是转换器,我更愿意理解为随便设计属性,根据设置的属性二次判断,适合于批量数据处理,感觉好鸡肋,不知道是不是自己没想到应用场景,该方法会把我们所有设置的数据该类型参数进行判断,记住,是所有,如果你设置int ,会判断所有int类型的,替换成你指定的数据,你没办法指定某个控件有效,也就是说,可能你是int引用类型引用的 color 值,但是他可以给你转成string字符串,你猜猜会不会崩?我感觉他唯一一的意义就是玩,唯一不会被他修改的就是没有使用他来设置属性。 * 如果说完全没有办法 那倒也不是,你可以设置参数类型跟返回值类型相同,比如color值,我们都可以用 R.string.;R.color. 这样的方式来使用,如果匹配不到,原路返回。 * 你可以这样理解,如果你使用DataBinding 设置的数据匹配到该方法,那么都会应用,当然,你自己原本写的不会有影响。

布局文件使用

android:text=”@{@string/aa}”

代码随便什么位置,反正看样子是全局匹配的 @BindingConversion public static String cc(String color) { switch (color) { case “aa”: return “ss”; case “bb”: return “rr”; } return “error”; }

结果就是 如果显示 ss

该方法是根据参数类型来匹配的,返回值类型跟参数类型都可以自定义

资源引用拼接(DataBinding)

设置

<string name="test">%1$s:%2$s</string>

引用

@{@string/test(user.name, user.age)}

结果

aa:bb
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表