Android DataBinding 高级用法
DataBinding快速上手,布局细节:
1.<data>...</data>标签内可以有多个 import 标签。你可以在布局文件中像使用 Java 一样导入引用。
2.当类名发生冲突时,可以使用 alias,像这样:
<data>
<import type="android.view.View"/>
<import type="com.wenzhibin.View"
alias="myView"/>
</data>
3.<data>...</data>标签内可以有任意数量的 variable 标签。每个 variable 标签描述了会在 binding 表达式中使用的属性。每个variable 标签里的name值就是 binding 类中的一个变量。
4.自动生成的 binding 类为每一个变量生成 getter/setter 函数。这些变量会使用 Java 的默认赋值,直到 setter 函数被调用。默认赋值有 null,0(int),false(boolean)等。如下例子:
在XML中,
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="studentModel" type="com.wenzhibin.StudentModel"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
自动生成的 binding 类中生成对应的 getter setter,
public abstract com.wenzhibin.StudentModel.getStudentModel();
public abstract void setStudentModel(com.wenzhibin.StudentModel studentModel);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);
5.当针对不同配置编写不同的布局文件时(比如横屏竖屏的布局),变量会被合并。所以这些不同配置的布局文件之间不能存在冲突。
6.导入也可以用于在表达式中使用静态方法,
例如:
public class StringUtils{
public static Stringnew(final String word){
if(word.length() >5) {
return word+“正在学习DataBinding的高级用法”;
}
return word;
}
}
<data>
<import type="com.wenzhibin.utils.StringUtils"/>
<variable name="studentModel" type="com.wenzhibin.StudentModel"/>
</data>
......
<TextView
android:text="@{StringUtils.Stringnew(studentModel.name)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
7.java.lang.* 包中的类会被自动导入,可以直接使用,例如, 要定义一个 String 类型的变量:
<variable name="note" type="String"/>
DataBinding高级用法:
1.列表绑定
RecyclerView数据绑定开源库:
evant / binding-collection-adapter
radzio / android-data-binding-recyclerview
如果觉得这两库不够灵活,可以自己封装。
2.自定义属性
绑定的时候,会调用 setXXX 方法,如果这个view提供该属性方法就可以通过 DataBinding 来设置,比如TextView 本身就内置了 setText(String text) 方法,只需要我们android:text="@{studentModel.name}",DataBinding就会自动寻找set方法------>setText(studentModel.namet) 上去,假设TextView没有 setText(String text)这个方法,这时就需要自定义属性了。有两种写法:
a)如果有类似的方法,方法名不一样,可以通过设置 BindingMethod来调用现有的方法。
比如 android:onClick,View 中没有 setOnClick 方法,但是有 setOnClickListener 方法,
这时候我们可以使用 BindingMethod(又称为Binding方法) 来做个映射。当在xml文件中看到"android:onClick"使用了DataBinding时,会把setOnClick映射到setOnClickListener上
@BindingMethods({
@BindingMethod(
type=View.class,
attribute="android:onClick",
method="setOnClickListener")
})
@BindingMethods 定义到类名上面。(ps:就是在某一个class类的前面加上上面这段代码,编译前会检查这个注释,然后作为一个Binding方法,自动调用)
当然,如果仅仅只是想重命名 setter方法,也可以通过 @BindingMethods 来实现。
b). 如果没有类似方法,可以通过设置BindingAdapter添加对应的方法。
比如 android:paddingRighttts,View 中是没有 setPaddingpaddingRighttts 方法的,只有 setPadding 方法。
这时候可以自定义一个 set 方法,并在方法上面添加 @BindingAdapter(又称为Binding适配器)。
//单个属性
@BindingAdapter("android:paddingRighttts")
public static void setPaddingRightRighttts(View view, int padding){
view.setPadding( view.getPaddingLeft(), view.getPaddingTop() ,padding, view.getPaddingBottom());
}
//多属性适配,同一个方法,可以同时设置多个属性
public class MyBindingAdapter {
@BindingAdapter({"imageUrl","placeholder"})
public static void loadImageFromUrl(ImageView view,String url,Drawable drawable) {
Glide.with(view.getContext()).load(url).placeholder(drawable).into(view);
}
}
在xml中使用,(MyBindingAdapter这个类的Binding适配器会自动调用)
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="studentModel" type="com.wenzhibin.StudentModel"/>
</data>
........
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
app:imageUrl="@{studentModel.headUri}"
app:placeholder="@{@drawable/default_headimg}"/>
(ps:如果这样写@BindingAdapter({"xxx"})或者是这样写@BindingAdapter({"bind:xxx"}),xml布局引用属性时这样写app:xxx="@{......}";如果这样写@BindingAdapter({"android:xxx"}),xml布局引用属性时这样写android:xxx="@{......}")
3.BindingConversion转换为setter需要的属性
<View
android:background= "@(isError ? @color/red : @color/white}"
android:layout_width= "wrap_content"
android:layout_height= "wrap_content" />
@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color);}
代码示例中,View的background属性需要的是Drawable,但是我们赋了color给它,通过 @BindingConversion 可以把color转换为Drawable,就可以使用color做background背景了。
4.双向绑定
一方面Model的变化会影响到UI界面的显示;另一方面UI界面的变化也会影响Model中对应字段的更新,简单来讲就是彼此相互影响,这就是双向绑定。在XML中使用”@=“就可以轻松实现双向绑定了。比如:<EditText android:text="@={studentModel.name}"/>
在XML中示例代码:
<data>
<variable
name="studentModel"
type="com.wenzhibin.StudentModel"/>
</data>
.......
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:text="@={studentModel.name}"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{studentModel.name}"/>
当用户输入时,<EditText>上的text会发生变化,text会直接赋给StudentModel的name属性,此时Button的text和<EditText>的text显示相同内容,因为StudentModel已经更新了。我们还可以监听属性变更,在java代码中如下示例:
studentModel.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable observable,int i) {
……..
do something
……..
}
5.表达式链
在XML出现重复的表达式:
<data>
<import type="android.view.View"/>
</data>
......
<ImageView android:visibility= "@{studentModel.isGraduate ? View.VISIBLE : View.GONE}" />
<TextView android:visibility= "@{studentModel.isGraduate ? View.VISIBLE : View.GONE}" />
<CheckBox android:visibility= "@{studentModel.isGraduate ? View.VISIBLE : View.GONE}" />
通过简化后的表达式:
<data>
<import type="android.view.View"/>
</data>
......
<ImageView
android:id= "@+id/img_head"
android:visibility= "@{studentModel.isGraduate ? View.VISIBLE : View.GONE}" />
<TextView android:visibility= "@{img_head.visibility}" />
<CheckBox android:visibility="@{img_head.visibility}"/>
隐式更新
<data>
<import type="android.view.View"/>
</data>
......
<CheckBox android:id= "@+id/isRemember" />
<ImageView android:visibility= "@{isRemember.checked? View.VISIBLE : View.GONE}" />
如上示例可以看出,我们不需要再去Java代码中判断CheckBox是否被选中,来控制图片的显示与隐藏。
6.lambda表达式
a)方法引用的替代者
android:onClick ="@ {(view)-> presenter.onUserClick(view,user)}”
b)省略参数,或申明所有参数(通常不需要view)
android:onClick ="@ {()-> presenter.onUserClick(user)}"
android:onFocusChange =“@{(v,fcs)-> presenter.onFocusChangelistner(user)}"
c)Lambda中可以使用表达式,引用变量
d)特殊变量:view id(传另一个View的驼峰变量名),包括context变量
示例代码:
在LambdaDemoActivity类中
public class LambdaDemoActivity extends AppCompatActivity {
private ActivityLambdaDemoBinding myBinding;
public class Presenter {
onUserClick(User user) {
Toast.makeText(LambdaDemoActivity.this,"onUserClick",
Toast.LENGTH_SHORT).show();
}
public void onUserLongClick(User user, Context mContext) {
Toast.makeText(mContext,"onUserLongClick",
Toast.LENGTH_SHORT).show();
}
public void onFocusChangelistner(User user) {
Toast.makeText(LambdaDemoActivity.this,"onFocusChangelistner",
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myBinding = DataBindingUtil.setContentView(this, R.layout.activity_lambda_demo);
myBinding.setUser(new User("wenzhibin","123456"));
myBinding.setPresenter(new Presenter());
}
}
在activity_lambda_demo.xml中
<data>
<variable name="presenter" type="com.wenzhibin.LambdaDemoActivity.Presenter"/>
<variable name="user" type="com.wenzhibin.User"/>
</data>
......
<Button android:onClick ="@ {()-> presenter.onUserClick(user)}"/>
(ps:下面这行代码是申明所有参数,这两个参数名可以随便写,可以不是v、fcs,只要两参数名不同就行。甚至省略所有参数,下面v、fcs这两个参数不写也是可以的。)
<Button android:onFocusChange =“@{(v,fcs)-> presenter.onFocusChangelistner(user)}"/>
<Button
android:text="@{user.loginName}"
(ps:在XML布局中我们并没有定义context这个变量,是databinding内部帮我们拿到了context,即拿到了这个activity)
android:onClick="@{(v) -> presenter.onUserLongClick(user, context)
}/>
7.动画
databinding已经封装了动画,我们只需要调用如下代码即可:
myBinding.addOnRebindCallback(new OnRebindCallback() {
@SuppressLint("NewApi")
@Override
public boolean onPreBind(ViewDataBinding binding) {
ViewGroup view = (ViewGroup) binding.getRoot();
TransitionManager.beginDelayedTransition(view);
return true;
}
});
今天的分享结束了,再见~