Android Data Binding 高级用法
来源:互联网 发布:世界十大灾难片 知乎 编辑:程序博客网 时间:2024/06/05 15:01
承接上一篇博客,Android Data Binding入门,这篇博客来看看Data Binding的高级用法。
1. 列表绑定
在Android中,列表是展示内容的最好方式,比如ListView、GridView、RecyclerView。前面我也写了一篇博客,介绍了RecyclerView的用法,请参考Android RecyclerViews实现下拉列表功能。这里用DataBinding绑定RecyclerView来实现一个列表,具体细节不在赘述,方法如下:
ListActivity.java
package com.jackie.sample.databinding;import android.databinding.DataBindingUtil;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.view.View;import android.widget.Toast;import com.jackie.sample.databinding.databinding.ActivityListBinding;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2016/10/29. */public class ListActivity extends AppCompatActivity { private ActivityListBinding mBinding; private EmployeeAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_list); mBinding.setPresenter(new Presenter()); mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); mAdapter = new EmployeeAdapter(this); mBinding.recyclerView.setAdapter(mAdapter); mAdapter.setListener(new EmployeeAdapter.OnItemClickListener() { @Override public void onItemClick(Employee employee) { Toast.makeText(ListActivity.this, employee.getFirstName(), Toast.LENGTH_SHORT).show(); } }); List<Employee> employeeList = new ArrayList<>(); employeeList.add(new Employee("Cheng1", "Jackie1", false)); employeeList.add(new Employee("Cheng2", "Jackie2", false)); employeeList.add(new Employee("Cheng3", "Jackie3", true)); employeeList.add(new Employee("Cheng4", "Jackie4", false)); mAdapter.addAll(employeeList); } public class Presenter { public void onClickAddItem(View view) { mAdapter.add(new Employee("Huang", "Ashia", false)); } public void onClickRemoveItem(View view) { mAdapter.remove(); } }}EmployeeAdapter.java
package com.jackie.sample.databinding;import android.content.Context;import android.databinding.DataBindingUtil;import android.databinding.ViewDataBinding;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;import java.util.Random;/** * Created by Administrator on 2016/10/29. */public class EmployeeAdapter extends RecyclerView.Adapter<BindingViewHolder> { private LayoutInflater mInflater; private OnItemClickListener mListener; private List<Employee> mEmployeeList; public static final int ITEM_VIEW_TYPE_ON = 1; public static final int ITEM_VIEW_TYPE_OFF = 2; public void setListener(OnItemClickListener listener) { this.mListener = listener; } public interface OnItemClickListener { void onItemClick(Employee employee); } public EmployeeAdapter(Context context) { mInflater = LayoutInflater.from(context); mEmployeeList = new ArrayList<>(); } @Override public int getItemViewType(int position) { Employee employee = mEmployeeList.get(position); if (employee.isFired()) { return ITEM_VIEW_TYPE_OFF; } else { return ITEM_VIEW_TYPE_ON; } } @Override public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ViewDataBinding binding; 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); } return new BindingViewHolder(binding); } @Override public void onBindViewHolder(BindingViewHolder holder, int position) { final Employee employee = mEmployeeList.get(position); holder.getBinding().setVariable(com.jackie.sample.databinding.BR.item_employee, employee); holder.getBinding().executePendingBindings(); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mListener != null) { mListener.onItemClick(employee); } } }); } @Override public int getItemCount() { return mEmployeeList.size(); } public void addAll(List<Employee> employeeList) { mEmployeeList.addAll(employeeList); } public void add(Employee employee) { int position = new Random().nextInt(mEmployeeList.size()) + 1; mEmployeeList.add(position, employee); notifyItemInserted(position); } public void remove() { if (mEmployeeList.size() == 0) { return; } int position = new Random().nextInt(mEmployeeList.size()); mEmployeeList.remove(position); notifyItemRemoved(position); }}BindingViewHolder.java
package com.jackie.sample.databinding;import android.databinding.ViewDataBinding;import android.support.v7.widget.RecyclerView;/** * Created by Administrator on 2016/10/29. */public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder { private T mBinding; public BindingViewHolder(T binding) { super(binding.getRoot()); mBinding = binding; } public T getBinding() { return mBinding; }}
activity_list.xml
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- 绑定 --> <data> <variable name="presenter" type="com.jackie.sample.databinding.ListActivity.Presenter"> </variable> </data> <LinearLayout 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"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{ presenter.onClickAddItem }" android:text="ADD"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{ presenter.onClickRemoveItem }" android:text="REMOVE"/> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout></layout>
效果如下:
2.自定义属性
默认的android命名空间下,我们会发现并不是所有的属性都能直接通过data binding进行设置,比如margin,padding,还有自定义View的各种属性。遇到这些属性,我们就需要自己去定义它们的绑定方法。
Setter
就像Data Binding会自动去查找get方法一下,在遇到属性绑定的时候,它也会去自动寻找对应的set方法。拿DrawerLayout举一个例子:
</android.support.v4.widget.drawerlayout>
如此,通过使用app命名空间,data binding就会去根据属性名字找对应的set方法,scrimColor -> setScrimColor:
public void setScrimColor(@ColorInt int color) { mScrimColor = color; invalidate();}如果找不到的话,就会在编译期报错。
利用这种特性,对一些第三方的自定义View,我们就可以继承它,来加上我们的set函数,以对其使用data binding。
比如Fresco的SimpleDraweeView,我们想要直接在xml指定url,就可以加上:
public void setUrl(String url) { view.setImageURI(TextUtils.isEmpty(url) ? null : Uri.parse(url));}这般,就能直接在xml中去绑定图片的url。这样是不是会比较麻烦呢,而且有一些系统的View,难道还要继承它们然后用自己实现的类?其实不然,我们还有其他方法可以做到自定义属性绑定。
BindingMethods
如果View本身就支持这种属性的set,只是xml中的属性名字和java代码中的方法名不相同呢?难道就为了这个,我们还得去继承View,使代码产生冗余?
当然没有这么笨,这时候我们可以使用BindingMethods注释。
android:tint是给ImageView加上着色的属性,可以在不换图的前提下改变图标的颜色。如果我们直接对android:tint使用data binding,由于会去查找setTint方法,而该方法不存在,则会编译出错。而实际对应的方法,应该是setImageTintList。
这时候我们就可以使用BindingMethod指定属性的绑定方法:
@BindingMethods({@BindingMethod(type = “android.widget.ImageView”, attribute = “android:tint”, method = “setImageTintList”),})我们也可以称BindingMethod为Setter重命名。
BindingAdapter
如果没有对应的set方法,或者方法签名不同怎么办?BindingAdapter注释可以帮我们来做这个。
比如View的android:paddingLeft属性,是没有对应的直接进行设置的方法的,只有setPadding(left, top, right, bottom),而我们又不可能为了使用Data Binding去继承修改这种基础的View(即便修改了,还有一堆继承它的View呢)。又比如那些margin,需要修改必须拿到LayoutParams,这些都无法通过简单的set方法去做。
这时候我们可以使用BindingAdapter定义一个静态方法:
@BindingAdapter("android:paddingLeft")public static void setPaddingLeft(View view, int padding) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());}事实上这个Adapter已经由Data Binding实现好了,可以在android.databinding.adapters.ViewBindingAdapter看到有很多定义好的适配器,还有BindingMethod。如果需要自己再写点什么,仿照这些来写就好了。
我们还可以进行多属性绑定,比如:
@BindingAdapter({"bind:imageUrl", "bind:error"})public static void loadImage(ImageView view, String url, Drawable error) { Picasso.with(view.getContext()).load(url).error(error).into(view);}
来使用Picasso读取图片到ImageView。
BindingConversion
有时候我们想在xml中绑定的属性,未必是最后的set方法需要的,比如我们想用color(int),但是view需要Drawable,比如我们想用String,而view需要的是Url。这时候我们就可以使用BindingConversion:
<view :="" android:background="“@{isError" android:layout_height="“wrap_content”/" android:layout_width="“wrap_content”" color="" red=""></view>@BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color);3.双向绑定
自定义Listener过去,我们需要自己定义Listener来做双向绑定:
<edittext android:aftertextchanged="“@{callback.change}”/" android:text="“@{user.name}”"></edittext>public void change(Editable s) { final String text = s.toString(); if (!text.equals(name.get()) { name.set(text); }}需要自己绑定afterTextChanged方法,然后检测text是否有改变,有改变则去修改observable。
新方式 - @=
现在可以直接使用@=(而不是@)来进行双向绑定了,使用起来十分简单:
<pre name="code" class="html"><edittext android:inputtype="textNoSuggestions" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@={model.name}"></edittext>
这样,我们对这个EditText的输入,就会自动set到对应model的name字段上。
实现如下:
activity_two_way.xml
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="model" type="com.jackie.sample.databinding.FormModel"/> </data> <LinearLayout 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"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textNoSuggestions" android:text="@={model.username}"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:text="@={model.password}"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{model.username}"/> </LinearLayout></layout>
TwoWayActivity.java
package com.jackie.sample.databinding;import android.databinding.DataBindingUtil;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import com.jackie.sample.databinding.databinding.ActivityTwoWayBinding;/** * Created by Administrator on 2016/10/29. */public class TwoWayActivity extends AppCompatActivity { private ActivityTwoWayBinding mBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_two_way); mBinding.setModel(new FormModel("jackie.cheng", "123456")); }}
FormModel.java
package com.jackie.sample.databinding;import android.databinding.BaseObservable;import android.databinding.Bindable;/** * Created by Administrator on 2016/10/29. */public class FormModel extends BaseObservable { private String username; private String password; @Bindable public String getUsername() { return username; } public void setUsername(String username) { this.username = username; notifyPropertyChanged(com.jackie.sample.databinding.BR.username); } @Bindable public String getPassword() { return password; } public void setPassword(String password) { this.password = password; notifyPropertyChanged(com.jackie.sample.databinding.BR.password); } public FormModel(String username, String password) { this.username = username; this.password = password; }}
效果如下:
3.Lambda表达式
在入门篇中有提到,可以参考。
4.动画
activity_animation.xml
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="android.view.View"/> <variable name="presenter" type="com.jackie.sample.databinding.AnimationActivity.Presenter"/> <variable name="showImage" type="boolean"/> </data> <LinearLayout 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"> <ImageView android:layout_width="100dp" android:layout_height="100dp" android:visibility="@{showImage ? View.VISIBLE : View.GONE}" android:src="@mipmap/ic_launcher"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:onCheckedChanged="@{presenter.onCheckedChanged}" android:text="显示图片"/> </LinearLayout></layout>添加动画:
- Android Data Binding 高级用法
- Android Data Binding高级
- Android Data Binding高级用法-Observable、动态生成Binding Class(三)
- Android Data Binding基础用法
- Android Data Binding实战-高级篇
- 【MVVM】Data Binding高级用法-Observable、动态生成Binding Class(三)
- 从零开始的Android新项目8 - Data Binding高级篇
- Android Data Binding 技术
- Android Data Binding学习
- Android Data Binding
- Android Data Binding
- android data binding
- Android Data Binding 技术
- Android Data Binding
- 精通 Android Data Binding
- Android Data Binding 技术
- Android Data Binding 用户指南
- Data Binding 用户指南(Android)
- robots.txt的作用
- Unreal Engine 4 C++ UCLASS构造函数易出错分析
- JAVA常用设计模式(2)工厂模式
- Adaboost 算法的原理与推导
- tcpdump
- Android Data Binding 高级用法
- 第八周实践都要学C
- vim delete
- Ubuntu 18.10可能取消对 32 位的支持!
- Java 实现最优路径查找算法(伪Leetcode路径查找算法)
- JZOJ 4822. 【NOIP2016提高A组集训第1场10.29】完美标号
- 编程常识
- 深入剖析Ehcache开源缓存框架
- Android中自定义控件