github地址:https://github.com/itlwy/DBindingView

写在前面

一个对databinding的常用封装库,包含基础控件及recycleview等。不了解databinding的可以先阅读相关网上的资料,这里推荐
Android DataBinding介绍

缩略图

normalWidget
normalWidget
recycleview
recycleview

如何引入

step1

Add the JitPack repository to your build file

allprojects {
                        repositories {
                                ...
                                maven { url 'https://jitpack.io' }
                        }
                }

step2

Add the dependency

dependencies {
                compile 'com.github.itlwy:DBindingView:v1.1.14'
        }

如何使用

一般控件

如上面的动态图,目前展示了基本控件的进行一些初始化的封装,目的是将一些繁琐的初始化操作自动化掉。注意,这里用到的属性均是自定义属性,前缀请用app:

涉及到的类





































































类名包名说明
KeyValuecom.lwy.dbindingview.data存储key(Integer)-value(String),主要用于spinner、checkbox、radiogroup等,实现数据源的key-label模式
BindingSpinnercom.lwy.dbindingview.bindingadapter.spinner封装的双向绑定自定义Spinner
DataBindingRadioGroupcom.lwy.dbindingview.bindingadapter.radiogroup封装的双向绑定自定义RadioGroup
DataBindingRadioButtoncom.lwy.dbindingview.bindingadapter.radiogroup封装的双向绑定自定义RadioButton
BindingCheckGroupcom.lwy.dbindingview.bindingadapter.checkbox封装的双向绑定自定义LinearLayout,用作BindingCheckBox容器
BindingCheckBoxcom.lwy.dbindingview.bindingadapter.checkbox封装的双向绑定自定义CheckBox
BindingEditTextcom.lwy.dbindingview.bindingadapter.edittext.BindingEditText让EditText支持绑定数值类型,eg:Integer、Double…

属性























































































































































































控件自定义属性值类型说明
BindingSpinnerselectedValueKeyValue 绑定选中的值
 spinneritemsList<KeyValue> spinner的适配器数据源
DataBindingRadioGroupselectedValueKeyValue 绑定RadioGroup选中的值
 itemsList<KeyValue> 设置该属性可动态渲染子view
 childViewFactoryDBCustomViewFactory<DataBindingRadioButton> 当设置了items属性时,可通过此属性传入继承自DataBindingRadioButton的自定义view,不设则用默认类
DataBindingRadioButtonvalueKeyValue 初始化RadioButton的值
BindingCheckGroupselectedValuesList<KeyValue> 存储checkbox选中的值,默认用,分割
 itemsList<KeyValue> 设置该属性可动态渲染子view
 childViewFactoryDBCustomViewFactory<BindingCheckBox> 当设置了items属性时,可通过此属性传入继承自BindingCheckBox的自定义view,不设则用默认类
BindingCheckBoxvalueKeyValue 设置值
ImageViewuriString or ObservableField 图片的url,用的加载框架是glide
 placeholderImageResinteg:R.mipmap.ic_launcher占位图
 request_width、request_widthint 设置图片的大小,不设置默认用view的大小,2个属性必修同时设置才有效
ViewclickCommandReplyCommand 点击事件触发的命令
 displayboolean 控制view的Visibility
BindingEdittexttextDouble、textInt、textFloat、textLongDouble、Float、Integer、Long 绑定数值类型
 regularExpression 正则表达式校验输入值 

具体使用很简单,直接看demo–>com.lwy.dbindingview.base_widget.WidgeActivity

这里说明下DataBindingRadioGroup和BindingCheckGroup,

<com.lwy.dbindingview.bindingadapter.radiogroup.DataBindingRadioGroup
                      android:layout_width="0dp"
                      android:layout_height="wrap_content"
                      android:layout_marginLeft="@dimen/margin_medium"
                      android:layout_marginRight="@dimen/margin_medium"
                      android:layout_weight="10"
                      android:orientation="horizontal"
                      app:items="@{viewmodel.sexList}"
                      app:childViewFactory="@{ViewFactory.createDBRadioButton()}"
                      app:selectedValue="@={viewmodel.sex}"/>

这里的app:items属性,让其根据sexList动态渲染子view(DataBindingRadioButton),也可以选择在布局里直接写子View,如:

<com.lwy.dbindingview.bindingadapter.radiogroup.DataBindingRadioGroup
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="@dimen/margin_medium"
                        android:layout_marginRight="@dimen/margin_medium"
                        android:layout_weight="10"
                        android:orientation="horizontal"
                        app:selectedValue="@={viewmodel.sex}">
                        <com.lwy.dbindingview.bindingadapter.radiogroup.DataBindingRadioButton
                            android:layout_width="wrap_content"
                            app:value="@{viewmodel.sex_male}"
                            android:layout_height="wrap_content"/>
                        <com.lwy.dbindingview.bindingadapter.radiogroup.DataBindingRadioButton
                            android:layout_width="wrap_content"
                            app:value="@{viewmodel.sex_female}"
                            android:layout_height="wrap_content"/>
                    </com.lwy.dbindingview.bindingadapter.radiogroup.DataBindingRadioGroup>

BindingCheckGroup同理

RecycleView

属性






















































































属性值类型说明
itemBindingItemBinding 必填,item的布局和变量的绑定关系包装类
itemsList<T> 必填,数据源
adapterBindingRecyclerViewAdapter<T> 选填,可继承BindingRecyclerViewAdapter自定义适配器
itemIdsBindingRecyclerViewAdapter.ItemIds<? super T> 选填,不设置则默认使用position
viewHolderBindingRecyclerViewAdapter.ViewHolderFactory 选填,可继承以实现自定义ViewHolder
onItemClickBindingRecyclerViewAdapter.OnItemClickListener item点击事件
layoutManagerLayoutManagers.LayoutManagerFactory 必填,布局方式,如线性:LayoutManagers.linear()
    

代码说明

  1. 单个布局的简单列表代码片段

    1、定义viewmodel

    public class ItemVM extends BaseObservable {
        public final boolean checkable; // for now,it's useless
        @Bindable
        private int index;
        @Bindable
        private boolean checked;
    
        public ItemVM(int index, boolean checkable) {
            this.index = index;
            this.checkable = checkable;
        }
    
        public int getIndex() {
            return index;
        }
    
        public boolean isChecked() {
            return checked;
        }
    
        public boolean onToggleChecked(View v) {
            if (!checkable) {
                return false;
            }
            checked = !checked;
    //        notifyPropertyChanged(com.lwy.dbindingview.BR.checked);
            return true;
        }
    }
    

    2、定义Item布局文件R.layout.item

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <data>
    
            <variable
                name="item"
                type="com.lwy.dbindingview.recycleview.vm.ItemVM" />
    
            <import type="android.view.View" />
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?selectableItemBackground"
            android:onLongClickListener="@{item::onToggleChecked}"
            android:longClickable="@{item.checkable}"
            android:orientation="horizontal">
    
            <TextView
                style="@style/TextAppearance.AppCompat.Body1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:padding="16dp"
                android:text='@{"Item " + (item.index + 1)}'
                tools:text="Item 1" />
    
            <ImageView
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:src="@mipmap/ic_action_check"
                android:visibility="@{item.checked ? View.VISIBLE : View.GONE}" />
        </LinearLayout>
    </layout>
    

    3、创建layout和viewmodel变量的绑定关系包装类

    public final ItemBinding<ItemVM> singleItem = ItemBinding.of(com.lwy.dbindingview.BR.item, R.layout.item);
    

    4、创建数据源

    public final ObservableList<ItemVM> items = new ObservableArrayList<>();
    

    5、设置RecycleView的属性

    ...
     <android.support.v7.widget.RecyclerView
                   android:id="@+id/list"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent"
                   app:itemBinding="@{viewmodel.singleItem}"
                   app:items="@{viewmodel.items}"
                   app:layoutManager="@{LayoutManagers.linear()}"/>
     ...
    
  2. 复杂布局代码片段

    1、定义viewmodel(同上)

    2、定义Item布局文件R.layout.item(同上)

    3、创建footer的viewmodel

    public class FooterVM extends RcVFooterVM {
    
        public final ReplyCommand clickCommand = new ReplyCommand(new Action0() {
            @Override
            public void call() {
                if (!getIsFooterLoading().get()) {
                    switchLoading(true);
                    callback.execute();
                }
    
            }
        });
    
        private ReplyCommand callback;
    
        public final ObservableField<String> noMoreTip = new ObservableField<>();
        /*
            state : 0 loading
            state : 1 idle
         */
        public final ObservableField<Integer> state = new ObservableField<>();


        public FooterVM(ReplyCommand callback) {
            super();
            this.callback = callback;
            switchLoading(false);
            noMoreTip.set("暂无更多");
        }

        @Override
        protected ReplyCommand<Integer> geneOnLoadMoreCommand() {
            return new ReplyCommand<>(new Action1<Integer>() {
                @Override
                public void call(Integer integer) {
                    FooterVM.this.callback.execute();
    //                switchLoading(true);
                }
            });
        }

        @Override
        public void switchLoading(boolean flag) {
            if (flag) {
                state.set(0);
            } else {
                state.set(1);
            }
            super.switchLoading(flag);
        }
    }

4、创建footer的布局文件R.layout.default_loading

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools">

        <data>

            <variable
                name="footerVM"
                type="com.lwy.dbindingview.recycleview.vm.FooterVM"/>
        </data>

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:clickCommand="@{footerVM.clickCommand}">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="45dp"
                android:gravity="center"
                android:orientation="horizontal"
                android:padding="8dp"
                app:display="@{footerVM.state==0?true:false}">

                <ProgressBar
                    android:layout_width="32dp"
                    android:layout_height="32dp"
                    />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="8dp"
                    android:text="正在加载..."
                    android:textSize="14sp"/>
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="45dp"
                android:gravity="center"
                android:orientation="horizontal"
                android:padding="8dp"
                app:display="@{footerVM.state==1?true:false}">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginLeft="8dp"
                    android:text="@{footerVM.noMoreTip}"
                    android:textSize="14sp"/>
            </LinearLayout>
        </LinearLayout>
    </layout>

5、创建layout和viewmodel变量的绑定关系包装类

    // 这里根据class类型来控制不同的item
    public final ItemBinding<Object> multipleItems = ItemBinding.of(new OnItemBindClass<>()
                .map(FooterVM.class, BR.footerVM, R.layout.default_loading)
                .map(String.class, com.lwy.dbindingview.BR.item, R.layout.item_header_footer)
                .map(ItemVM.class, com.lwy.dbindingview.BR.item, R.layout.item));

6、创建数据源

    public final FooterVM footerVM = new FooterVM(new ReplyCommand<Integer>(new Action1<Integer>() {

            @Override
            public void call(Integer integer) {
                // 异步执行加载数据 完了需要调用 "footerVM.switchLoading(false)" 取消加载状态
            }
        }));

    public final ObservableList<ItemVM> items = new ObservableArrayList<>();
    public final MergeObservableList<Object> headerFooterItems = new MergeObservableList<>()
                .insertItem("Header")
                .insertList(items)
                .insertItem(footerVM);

5、设置RecycleView的属性

    ...
    <android.support.v7.widget.RecyclerView
                   android:id="@+id/list"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent"
                   app:itemBinding="@{viewmodel.multipleItems}"
                   app:items="@{viewmodel.headerFooterItems}"
                   app:layoutManager="@{LayoutManagers.linear()}"/>
    ...

参考

  1. binding-collection-adapter