配色: 字号:
Android Data Binding 高级用法
2017-01-03 | 阅:  转:  |  分享 
  
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">




android:layout_width="match_parent"

android:layout_height="wrap_content"

android:onClick="@{presenter.onClickAddItem}"

android:text="ADD"/>




android:layout_width="match_parent"

android:layout_height="wrap_content"

android:onClick="@{presenter.onClickRemoveItem}"

android:text="REMOVE"/>




android:id="@+id/recycler_view"

android:layout_width="match_parent"

android:layout_height="wrap_content"/>





效果如下:





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="显示图片"/>







献花(0)
+1
(本文系thedust79首藏)