官方文档
配置 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);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标签中
<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(); }});布局文件中
<TextView android:id="@+id/show" android:layout_width="wrap_content" android:layout_height="wrap_content"/>代码中
binding.show.setText("Test");重定义 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 找到了。在 布局文件引用在 代码中设置展示的数据。代码实现
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();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();首先,自定义命名空间(万能命名空间 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);}说是转换器,我更愿意理解为随便设计属性,根据设置的属性二次判断,适合于批量数据处理,感觉好鸡肋,不知道是不是自己没想到应用场景,该方法会把我们所有设置的数据该类型参数进行判断,记住,是所有,如果你设置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
该方法是根据参数类型来匹配的,返回值类型跟参数类型都可以自定义设置
<string name="test">%1$s:%2$s</string>引用
@{@string/test(user.name, user.age)}结果
aa:bb新闻热点
疑难解答