2019-08-13 databinding 简单使用
使用databinding首先得打开 databinding,在app目录下的build.gradle 中配置
android {
compileSdkVersion 29
buildToolsVersion "29.0.1"
defaultConfig {
//......
}
//开启databinding
dataBinding {
enabled = true
}
}
这样就可以使用databinding的功能,使用databinding需要生成一个xxxBinding,所以需要编写xml文件
<?xml version="1.0" encoding="utf-8"?>
<!--使用databinding ,最外层的节点必须是 layout-->
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.example.test.view.LoginActivity">
<!--data 节点定义对应的数据,如下,我定义了LoginActivity 为view-->
<!--定义了 LoginViewModel 为 viewmodel-->
<!--定义之后在下面就可以使用-->
<data>
<variable name="view"
type="com.example.test.view.LoginActivity"/>
<variable name="viewmodel"
type="com.example.test.viewmodel.LoginViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="@{viewmodel.text}"
android:onClick="@{() -> viewmodel.login()}"
android:id="@+id/bt_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_login"
app:layout_constraintTop_toBottomOf="@+id/bt_login"
android:layout_width="match_parent"
app:activity="@{view}"
app:beans="@{viewmodel.mLoginBean}"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
上面<data>节点主要用于引入需要的类或者数据,上面我引入了 LoginActivity 和 LoginViewModel 这两个类,后面的设置再说。编写到这里,编译项目,就会生成 xxxBinding 类(xxx 是这个xml 的名称,比如我的xml 为 login_activiy.xml 对应生成的为 LoginActivityBinding),然后在对应的Activity 的onCreate 方法中绑定
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//通过 DataBindingUtil 获取 ActivityLoginBinding 对象
var dataBinding = DataBindingUtil.setContentView<ActivityLoginBinding>(this, R.layout.activity_login)
//将当前Activity 设置给 dataBinding.view
//注意 dataBinding.view 就是在编写xml 时候<data>节点下的view
dataBinding.view = this
//将 viewmodel 赋值
dataBinding.viewmodel = LoginViewModel(application, LoginModel())
}
对于TextView和Button
到这里,databinding 就设置完成。下面来介绍使用databinding来设置文本信息
<Button
android:text="@{viewmodel.text}"
android:onClick="@{() -> viewmodel.login()}"
android:id="@+id/bt_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints"/>
我们只需要在text中直接text ="@{xxx}"就可以设置button的文本信息,我这里使用viewmodel.text ,所以需要在LoginViewModel中定义text属性
open class LoginViewModel(application: Application, model: LoginModel) : BaseViewModel<LoginModel>(application, model) {
var mLoginBean: ObservableArrayList<BaseBean> = ObservableArrayList()
//定义text,就可以直接在xml中使用
var text: String = "login"
}
如果想动态修改text内容,则将text = "@={xxx.xxx}" @后增加一个等号,并且使用 ObservableField 来做数据双向绑定,这样修改数据时,就能相应的显示在界面上
<Button
android:text="@={viewmodel.text}"
android:onClick="@{() -> viewmodel.login()}"
android:id="@+id/bt_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints"/>
open class LoginViewModel(application: Application, model: LoginModel) : BaseViewModel<LoginModel>(application, model) {
var mLoginBean: ObservableArrayList<BaseBean> = ObservableArrayList()
var text = ObservableField<String>()
init {
text.set("login")
}
}
关于设置点击事件,则在xml 中设置android:onClick="@{()->viewmodel.login()}" ,然后在 viewmodel 中创建login 方法
open class LoginViewModel(application: Application, model: LoginModel) : BaseViewModel<LoginModel>(application, model) {
var mLoginBean: ObservableArrayList<BaseBean> = ObservableArrayList()
var text = ObservableField<String>()
init {
text.set("login")
}
fun login() {
//点击事件,就会进来这里
}
}
这样,点击事件就会进来的 login方法中,如果需要在点击事件中传递参数,则在xml中
<Button
android:text="@={viewmodel.text}"
android:onClick="@{(it) -> viewmodel.login(it)}"
android:id="@+id/bt_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints"/>
将 android:onClick="@{(it) -> viewmodel.login(it)}" ,这里的it可以任意填写,代表当前view本身,如果需要其他参数,在viewmodel.login(it,params.....)中添加即可,在LoginViewModel修改对应的方法:
open class LoginViewModel(application: Application, model: LoginModel) :
BaseViewModel<LoginModel>(application, model) {
var mLoginBean: ObservableArrayList<BaseBean> = ObservableArrayList()
var text = ObservableField<String>()
init {
text.set("login")
}
//添加了什么参数,就加上对应的参数即可
fun login(view: View) {
//点击事件,就会进来这里
}
}
对于ImageView
imagview 主要设置图片,在任意地方新建一个类:
public class BindingImageLoad {
@BindingAdapter({"app:image"})
public static void setImage(ImageView image, String url) {
Log.e("TAG", "---->" + url);
}
}
使用@BindingAdapter 注解,配置需要的参数,在xml中使用
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:image="@{activity.image}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bt_click" />
xml 中会出现@BindingAdapter注解中配置的参数,然后就会调用@BindingAdapter注解的方法,在这个方法里就可以用自己的方式来设置图片
对于RecyclerView
对于recycleview,和imageview一样,在任意地方创建类
public class BindingAdapterInit {
/**
* 设置 LinearLayout 样式的 recyclerView
*
* @param recyclerView recyclerView 自身
* @param beans 数据集
* @param activity 当前activity
*/
@BindingAdapter({"app:beans", "app:context"})
public static void setLinearRecycler(RecyclerView recyclerView, List<BaseBean> beans, Context activity) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter == null) {
//创建adapter
} else {
adapter.notifyDataSetChanged();
}
}
}
和imagview一样,添加注解,最后会回调到这个方法中,在这里面可以设置RecyclerView的Adapter,关于RecyclerView 的item,如果也想使用,则需要修改一下Adapter
public abstract class BaseBindingAdapter extends RecyclerView.Adapter<BaseBindingAdapter.MyHolder> {
protected Context context;
public BaseBindingAdapter(Context context) {
this.context = context;
}
@NonNull
@Override
public BaseBindingAdapter.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//获取Binding
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), getLayoutId(), parent, false);
return new MyHolder(binding.getRoot());
}
@Override
public void onBindViewHolder(@NonNull BaseBindingAdapter.MyHolder holder, int position) {
//注意需要调用executePendingBindings通知数据改变
//没有调用可能数据改变了,视图没有改变
ViewDataBinding binding = DataBindingUtil.getBinding(holder.itemView);
setView(binding, holder, position);
binding.executePendingBindings();
}
public abstract int getLayoutId();
public abstract void setView(BaseBindingAdapter.MyHolder holder, int position);
public class MyHolder extends RecyclerView.ViewHolder {
public MyHolder(@NonNull View itemView) {
super(itemView);
}
}
}
写一个类似这样的Adapte就可以在Item中也使用Binding了
对于include
如果需要使用include需要在include标签中添加bind:xxx,如下
<include
android:id="@+id/no_net"
layout="@layout/fragment_home_not_net"
android:visibility="gone"
bind:viewmodel="@{viewmodel}" />
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewmodel"
type="com.dunya.muslims.viewmodel.HomeViewModel" />
</data>
......
</layout>
在上面中,我需要传一个HomeViewModel过来,定义的名字为viewmodel,所以在include标签中添加bind:viewmodel,需要什么就bind:xxx 即可