Android DataBinding 自定义 View 的双向绑定

本篇文章着重于写怎么实现DataBinding自定义 View 的双向绑定,理论和定义不再赘述。理论和定义可以参考这两篇博文:

Android DataBinding (五) 自定义 View 的双向绑定

Databinding的使用(自定义控件的全局注入、布局绑定)

当然,这两篇博文也有具体实现的代码,十分感谢这两篇博主的博文参考!

首先说明一下这个自定义view的功能:MultiSelectionSpinner(自定义单多选Spinner),点击控件时弹出供单选或多选的Dialog,见下图。当点击确定时会调用回调接口与viewmodel进行属性绑定。

实现步骤如下:

1、自定义MultiSelectionSpinner类

要支持双向绑定,首先要在类名上定义 @InverseBindingMethods

@InverseBindingMethods({
    @InverseBindingMethod(
        type = MultiSelectionSpinner.class,
        attribute = "selectConfirm",
        event = "selectConfirmAttrChanged",
        method = "getSelectConfirm")
})
public class MultiSelectionSpinner extends AppCompatSpinner implements DialogInterface.OnClickListener,OnMultiChoiceClickListener {

    ………………………… // 自定义view具体逻辑实现代码
    
    public interface OnSelectConfirmListener{
        void onSelectConfirm();
    }

    private OnSelectConfirmListener mListener;

    public void setOnSelectConfirmListener(OnSelectConfirmListener listener) {
        mListener = listener;
    }

    @InverseBindingAdapter(attribute = "selectConfirm", event="selectConfirmAttrChanged")
    public static String getSelectConfirm(MultiSelectionSpinner view) {
        return view.getSelectedItemsAsString();
    }

    @BindingAdapter({"selectConfirm"})
    public static void setSelectConfirm(MultiSelectionSpinner spinner, String item){
        if(item!=null){
           spinner.setSelection(Arrays.asList(item.split("\\,")));
        }
    }

    @BindingAdapter(value = {"onSelectConfirm", "selectConfirmAttrChanged"}, requireAll = false)
    public static void setOnValueSelectListener(MultiSelectionSpinner view,
           final OnSelectConfirmListener onSelectConfirmListener,final InverseBindingListener bindingListener) {

        if (bindingListener == null) {
            view.setOnSelectConfirmListener(onSelectConfirmListener);
        } else {

            view.setOnSelectConfirmListener(new OnSelectConfirmListener() {
                @Override
                public void onSelectConfirm() {
                    if(onSelectConfirmListener!=null){
                        onSelectConfirmListener.onSelectConfirm();
                    }else{
                        // 通知 ViewModel
                        bindingListener.onChange();
                    }
                }
            });
        }
    }
    
    @SuppressLint("ClickableViewAccessibility")
	@Override 
    public boolean performClick() {
    	
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        //builder.setMultiChoiceItems(_items, mSelection, this);

        if(!setSingleChoice){                                                       // 多选
            builder.setMultiChoiceItems(_items, mSelection, this);
        }else{
            builder.setSingleChoiceItems(_items, mChoice,this);             // 单选
        }

        _itemsAtStart = getSelectedItemsAsString();
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            // Dialog 确定按钮点击事件,调用onSelectConfirm接口实现与viewmodel属性进行绑定
            @Override
            public void onClick(DialogInterface dialog, int which) {
                System.arraycopy(mSelection, 0, mSelectionAtStart, 0, mSelection.length);
                if(mListener!=null){
                    mListener.onSelectConfirm();
                }
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                simple_adapter.clear();
                simple_adapter.add(_itemsAtStart);
                System.arraycopy(mSelectionAtStart, 0, mSelection, 0, mSelectionAtStart.length);
            }
        });
        builder.show();
        return true;
    }

}

2、布局文件xml中用app:selectConfirm="@={}"与viewmodel进行双向绑定。注:下面代码只是截取了布局xml中婚否那一部分

         <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="50dp">

            <TextView
                android:layout_weight="1.5"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:textSize="20sp"
                android:gravity="center"
                android:text="(单选) 婚否"/>

            <com.mvvmdemo.MultiSelectionSpinner
                android:layout_weight="2"
                android:layout_width="0dp"
                android:layout_height="40dp"
                android:entries="@array/ifnot"
                android:textSize="18sp"
                android:background="@drawable/spinner_bg"
                custom:custom_gravity="center"
                custom:singleChoice="true"
                app:selectConfirm="@={simple.marriage}"/>

        </LinearLayout>

2、Activity实现效果

public class BlogActivity extends AppCompatActivity implements View.OnClickListener{

    private ActivityBlogBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding=DataBindingUtil.setContentView(this,R.layout.activity_blog);
        binding.setSimple(new SimpleEntity("是","篮球"));
        binding.setClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_blog_save:
                SimpleEntity simple=binding.getSimple();
                Toast.makeText(BlogActivity.this,simple.toString(),Toast.LENGTH_SHORT).show();
                break;
                default:
        }
    }
}

 

运行过程分析:

1、Activity在onCreate()设置布局并且绑定viewmodel后即会调用MultiSelectionSpinner类中设置的 @BindingAdapter({"selectConfirm"}),此时界面上自定义MultiSelectionSpinner即会分别显示我们设置的"是"和"篮球",同时会调用MultiSelectionSpinner类中的监听事件 setOnValueSelectListener()设置确定按钮点击回调接口。

2、当点击自定义MultiSelectionSpinner弹出Dialog选择完毕点击确定后即会进入1设置好的回调事件中调用 bindingListener.onChange(); 通知 ViewModel要改变viewl,接着会调用之前在 MultiSelectionSpinner类中的绑定好的 @InverseBindingAdapter  getSelectConfirm(),在该方法中获取到选择的值后就会把值返回给@BindingAdapter({"selectConfirm"}),由该Adapter把选择值显示在Activity的View上。

至此自定义 View 的双向绑定完成。

水平有限,欢迎批评指正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值