2019-08-13 databinding 简单使用

2019-11-01  本文已影响0人  猫KK

使用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 即可

上一篇下一篇

猜你喜欢

热点阅读