AndroidDataBinding高级用法
1.列表绑定
在Android中,列表是展示内容的最好方式,比如ListView、GridView、RecyclerView。前面我也写了一篇博客,介绍了RecyclerView的用法,请参考AndroidRecyclerViews实现下拉列表功能。这里用DataBinding绑定RecyclerView来实现一个列表,具体细节不在赘述,方法如下:
ListActivity.Java
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.jackie.sample.databinding;
importandroid.databinding.DataBindingUtil;
importandroid.os.Bundle;
importandroid.support.v7.app.AppCompatActivity;
importandroid.support.v7.widget.LinearLayoutManager;
importandroid.view.View;
importandroid.widget.Toast;
importcom.jackie.sample.databinding.databinding.ActivityListBinding;
importjava.util.ArrayList;
importjava.util.List;
/
CreatedbyAdministratoron2016/10/29.
/
publicclassListActivityextendsAppCompatActivity{
privateActivityListBindingmBinding;
privateEmployeeAdaptermAdapter;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
mBinding=DataBindingUtil.setContentView(this,R.layout.activity_list);
mBinding.setPresenter(newPresenter());
mBinding.recyclerView.setLayoutManager(newLinearLayoutManager(this));
mAdapter=newEmployeeAdapter(this);
mBinding.recyclerView.setAdapter(mAdapter);
mAdapter.setListener(newEmployeeAdapter.OnItemClickListener(){
@Override
publicvoidonItemClick(Employeeemployee){
Toast.makeText(ListActivity.this,employee.getFirstName(),Toast.LENGTH_SHORT).show();
}
});
ListemployeeList=newArrayList<>();
employeeList.add(newEmployee("Cheng1","Jackie1",false));
employeeList.add(newEmployee("Cheng2","Jackie2",false));
employeeList.add(newEmployee("Cheng3","Jackie3",true));
employeeList.add(newEmployee("Cheng4","Jackie4",false));
mAdapter.addAll(employeeList);
}
publicclassPresenter{
publicvoidonClickAddItem(Viewview){
mAdapter.add(newEmployee("Huang","Ashia",false));
}
publicvoidonClickRemoveItem(Viewview){
mAdapter.remove();
}
}
}
EmployeeAdapter.java
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.jackie.sample.databinding;
importandroid.content.Context;
importandroid.databinding.DataBindingUtil;
importandroid.databinding.ViewDataBinding;
importandroid.support.v7.widget.RecyclerView;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.Random;
/
CreatedbyAdministratoron2016/10/29.
/
publicclassEmployeeAdapterextendsRecyclerView.Adapter{
privateLayoutInflatermInflater;
privateOnItemClickListenermListener;
privateListmEmployeeList;
publicstaticfinalintITEM_VIEW_TYPE_ON=1;
publicstaticfinalintITEM_VIEW_TYPE_OFF=2;
publicvoidsetListener(OnItemClickListenerlistener){
this.mListener=listener;
}
publicinterfaceOnItemClickListener{
voidonItemClick(Employeeemployee);
}
publicEmployeeAdapter(Contextcontext){
mInflater=LayoutInflater.from(context);
mEmployeeList=newArrayList<>();
}
@Override
publicintgetItemViewType(intposition){
Employeeemployee=mEmployeeList.get(position);
if(employee.isFired()){
returnITEM_VIEW_TYPE_OFF;
}else{
returnITEM_VIEW_TYPE_ON;
}
}
@Override
publicBindingViewHolderonCreateViewHolder(ViewGroupparent,intviewType){
ViewDataBindingbinding;
if(viewType==ITEM_VIEW_TYPE_ON){
binding=DataBindingUtil.inflate(mInflater,R.layout.item_employee_on,parent,false);
}else{
binding=DataBindingUtil.inflate(mInflater,R.layout.item_employee_off,parent,false);
}
returnnewBindingViewHolder(binding);
}
@Override
publicvoidonBindViewHolder(BindingViewHolderholder,intposition){
finalEmployeeemployee=mEmployeeList.get(position);
holder.getBinding().setVariable(com.jackie.sample.databinding.BR.item_employee,employee);
holder.getBinding().executePendingBindings();
holder.itemView.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
if(mListener!=null){
mListener.onItemClick(employee);
}
}
});
}
@Override
publicintgetItemCount(){
returnmEmployeeList.size();
}
publicvoidaddAll(ListemployeeList){
mEmployeeList.addAll(employeeList);
}
publicvoidadd(Employeeemployee){
intposition=newRandom().nextInt(mEmployeeList.size())+1;
mEmployeeList.add(position,employee);
notifyItemInserted(position);
}
publicvoidremove(){
if(mEmployeeList.size()==0){
return;
}
intposition=newRandom().nextInt(mEmployeeList.size());
mEmployeeList.remove(position);
notifyItemRemoved(position);
}
}
BindingViewHolder.java
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.jackie.sample.databinding;
importandroid.databinding.ViewDataBinding;
importandroid.support.v7.widget.RecyclerView;
/
CreatedbyAdministratoron2016/10/29.
/
publicclassBindingViewHolderextendsRecyclerView.ViewHolder{
privateTmBinding;
publicBindingViewHolder(Tbinding){
super(binding.getRoot());
mBinding=binding;
}
publicTgetBinding(){
returnmBinding;
}
}
activity_list.xml
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
xmlns:tools="http://schemas.android.com/tools">
name="presenter"
type="com.jackie.sample.databinding.ListActivity.Presenter">
android:id="@+id/activity_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.jackie.sample.databinding.ListActivity"
android:orientation="vertical">
效果如下:
2.自定义属性
默认的android命名空间下,我们会发现并不是所有的属性都能直接通过databinding进行设置,比如margin,padding,还有自定义View的各种属性。遇到这些属性,我们就需要自己去定义它们的绑定方法。
Setter
就像DataBinding会自动去查找get方法一下,在遇到属性绑定的时候,它也会去自动寻找对应的set方法。拿DrawerLayout举一个例子:
如此,通过使用app命名空间,databinding就会去根据属性名字找对应的set方法,scrimColor->setScrimColor:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
publicvoidsetScrimColor(@ColorIntintcolor){
mScrimColor=color;
invalidate();
}
如果找不到的话,就会在编译期报错。
利用这种特性,对一些第三方的自定义View,我们就可以继承它,来加上我们的set函数,以对其使用databinding。
比如Fresco的SimpleDraweeView,我们想要直接在xml指定url,就可以加上:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
publicvoidsetUrl(Stringurl){
view.setImageURI(TextUtils.isEmpty(url)?null:Uri.parse(url));
}
这般,就能直接在xml中去绑定图片的url。这样是不是会比较麻烦呢,而且有一些系统的View,难道还要继承它们然后用自己实现的类?其实不然,我们还有其他方法可以做到自定义属性绑定。
BindingMethods
如果View本身就支持这种属性的set,只是xml中的属性名字和java代码中的方法名不相同呢?难道就为了这个,我们还得去继承View,使代码产生冗余?
当然没有这么笨,这时候我们可以使用BindingMethods注释。
android:tint是给ImageView加上着色的属性,可以在不换图的前提下改变图标的颜色。如果我们直接对android:tint使用databinding,由于会去查找setTint方法,而该方法不存在,则会编译出错。而实际对应的方法,应该是setImageTintList。
这时候我们就可以使用BindingMethod指定属性的绑定方法:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
@BindingMethods({
@BindingMethod(type=“android.widget.ImageView”,
attribute=“android:tint”,
method=“setImageTintList”),
})
我们也可以称BindingMethod为Setter重命名。
BindingAdapter
如果没有对应的set方法,或者方法签名不同怎么办?BindingAdapter注释可以帮我们来做这个。
比如View的android:paddingLeft属性,是没有对应的直接进行设置的方法的,只有setPadding(left,top,right,bottom),而我们又不可能为了使用DataBinding去继承修改这种基础的View(即便修改了,还有一堆继承它的View呢)。又比如那些margin,需要修改必须拿到LayoutParams,这些都无法通过简单的set方法去做。
这时候我们可以使用BindingAdapter定义一个静态方法:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
@BindingAdapter("android:paddingLeft")
publicstaticvoidsetPaddingLeft(Viewview,intpadding){
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
事实上这个Adapter已经由DataBinding实现好了,可以在android.databinding.adapters.ViewBindingAdapter看到有很多定义好的适配器,还有BindingMethod。如果需要自己再写点什么,仿照这些来写就好了。
我们还可以进行多属性绑定,比如:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
@BindingAdapter({"bind:imageUrl","bind:error"})
publicstaticvoidloadImage(ImageViewview,Stringurl,Drawableerror){
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
来使用Picasso读取图片到ImageView。
BindingConversion
有时候我们想在xml中绑定的属性,未必是最后的set方法需要的,比如我们想用color(int),但是view需要Drawable,比如我们想用String,而view需要的是Url。这时候我们就可以使用BindingConversion:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
@BindingConversion
publicstaticColorDrawableconvertColorToDrawable(intcolor){
returnnewColorDrwww.tt951.comawable(color);
3.双向绑定
自定义Listener过去,我们需要自己定义Listener来做双向绑定:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
publicvoidchange(Editables){
finalStringtext=s.toString();
if(!text.equals(name.get()){
name.set(text);
}
}
需要自己绑定afterTextChanged方法,然后检测text是否有改变,有改变则去修改observable。
新方式-@=
现在可以直接使用@=(而不是@)来进行双向绑定了,使用起来十分简单:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
这样,我们对这个EditText的输入,就会自动set到对应model的name字段上。
实现如下:
activity_two_way.xml
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
xmlns:tools="http://schemas.android.com/tools">
name="model"
type="com.jackie.sample.databinding.FormModel"/>
android:id="@+id/activity_two_way"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jackie.sample.databinding.TwoWayActivity"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:text="@={model.username}"/>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:text="@={model.password}"/>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{model.username}"/>
TwoWayActivity.java
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.jackie.sample.databinding;
importandroid.databinding.DataBindingUtil;
importandroid.os.Bundle;
importandroid.support.v7.app.AppCompatActivity;
importcom.jackie.sample.databinding.databinding.ActivityTwoWayBinding;
/
CreatedbyAdministratoron2016/10/29.
/
publicclassTwoWayActivityextendsAppCompatActivity{
privateActivityTwoWayBindingmBinding;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
mBinding=DataBindingUtil.setContentView(this,R.layout.activity_two_way);
mBinding.setModel(newFormModel("jackie.cheng","123456"));
}
}
FormModel.java
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
packagecom.jackie.sample.databinding;
importandroid.databinding.BaseObservable;
importandroid.databinding.Bindable;
/
CreatedbyAdministratoron2016/10/29.
/
publicclassFormModelextendsBaseObservable{
privateStringusername;
privateStringpassword;
@Bindable
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
notifyPropertyChanged(com.jackie.sample.databinding.BR.username);
}
@Bindable
publicStringgetPassword(){
returnpassword;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
notifyPropertyChanged(com.jackie.sample.databinding.BR.password);
}
publicFormModel(Stringusername,Stringpassword){
this.username=username;
this.password=password;
}
}
效果如下:
3.Lambda表达式
在入门篇中有提到,可以参考。
4.动画
activity_animation.xml
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
xmlns:tools="http://schemaswww.baiyuewang.net.android.com/tools">
name="presenter"
type="com.jackie.sample.databinding.AnimationActivity.Presenter"/>
name="showImage"
type="boolean"/>
android:id="@+id/activity_animation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.jackie.sample.databinding.AnimationActivity"
android:orientation="vertical">
android:layout_width="100dp"
android:layout_height="100dp"
android:visibility="@{showImage?View.VISIBLE:View.GONE}"
android:src="@mipmap/ic_launcher"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{presenter.onCheckedChanged}"
android:text="显示图片"/>
|
|