1. 程式人生 > >android-Data Binding+recycleview打造二三級都可以選擇的三級列表

android-Data Binding+recycleview打造二三級都可以選擇的三級列表

效果圖

這裡寫圖片描述

這是前段時間做得一個專案需求,要求能夠選擇選擇第二級和第三級的一個三級列表,話不多說了,看程式碼吧

一、專案配置

由於這個專案早期的框架用的是databing,關於databing的一些介紹就不寫了,只是貼出來一些gradle的必要的配置

//這個是databing的
android {
    dataBinding {
        enabled = true
    }
}

//這是用到的依賴包,個人習慣,可以根據自己的方式調整
  compile 'io.reactivex:rxjava:1.2.4'
 compile 'io.reactivex:rxandroid:1.2.1'
compile 'com.kelin.mvvmlight:library:1.0.0' //一個Android MVVM 輕量級工具庫,裡面添加了一些Data Binding 不支援的屬性,還有新增對控制元件事件的封裝,同時提個一個全域性訊息通道方便ViewModel 之間的通訊,Toolkit主要包括兩部分Binding和Messenger compile 'com.google.code.gson:gson:2.2.4'//用來解析json的

二、程式碼和佈局
activity_choice_job_category.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:bind="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="android.view.View" /> <import type="me.tatarka.bindingcollectionadapter.LayoutManagers"
/>
<variable name="viewModel" type="com.daxue.databingtestdemo.viewmodel.JobCategoryViewModel" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.daxue.databingtestdemo.activity.ChoiceJobCategoryActivity"> <TextView android:layout_width="match_parent" android:layout_height="45dp" android:background="@color/colorPrimary" android:text="選擇" android:textColor="@color/white" android:gravity="center"/> <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:background="@color/bg_gray" android:orientation="horizontal" android:visibility="@{viewModel.showLabel ? View.VISIBLE : View.GONE}"> <TextView style="@style/textStyle" android:layout_width="100dp" android:layout_height="wrap_content" android:text="@{viewModel.leftText}" bind:clickCommand="@{viewModel.leftTextClickCommand}" android:visibility="@{viewModel.leftVisible ? View.VISIBLE : View.GONE}" /> <TextView style="@style/textStyle" android:layout_width="100dp" android:layout_height="wrap_content" android:text="@{viewModel.middleText}" bind:clickCommand="@{viewModel.middleTextClickCommand}" android:visibility="@{viewModel.middleVisible ? View.VISIBLE : View.GONE}" /> <TextView style="@style/textStyle" android:layout_width="100dp" android:layout_height="wrap_content" android:text="@{viewModel.rightText}" bind:clickCommand="@{viewModel.rightTextClickCommand}" android:visibility="@{viewModel.rightVisible ? View.VISIBLE : View.GONE}" /> </LinearLayout> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" bind:itemView="@{viewModel.itemView}" bind:items="@{viewModel.itemViewModels}" bind:layoutManager="@{LayoutManagers.linear()}" /> </LinearLayout> </layout>

Data Binding的好處,直接用精簡的程式碼實現資料與UI和邏輯的繫結,不需要編寫大量的毫無營養繁瑣的的程式碼,如 findViewById()、setText(),setVisibility(),setEnabled() 或 setOnClickListener() 等通通不需要

ChoiceJobCategoryActivity.java

public class ChoiceJobCategoryActivity extends AppCompatActivity {
    private ActivityChoiceJobCategoryBinding binding;//這個是自動生成滴
    private JobCategoryViewModel viewModel;
    private ArrayList<TreeModel> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        viewModel = new JobCategoryViewModel(this);
        //前面帶過來已選中的資料
        list = getIntent().getParcelableArrayListExtra("selected");
        if (list != null) {
            viewModel.setChoicePositions(list);
        }

        binding = DataBindingUtil.setContentView(this, R.layout.activity_choice_job_category);
        binding.setViewModel(viewModel);
        viewModel.start();
    }

    public void initLayout() {
        binding.recyclerView.getAdapter().notifyDataSetChanged();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Messenger.getDefault().unregister(this);
    }
}

這個頁面實際上是一個過渡頁面,起到一個橋樑的作用,實現activity與佈局的繫結,主要的邏輯在viewmodel裡面去實現

恩,下面才是重頭戲

JobCategoryViewModel

public class JobCategoryViewModel extends BaseViewModel {
    public static final String TAG = JobCategoryViewModel.class.getSimpleName();
    public static final String EXTRA_SINGLE = "single";
    private ChoiceJobCategoryActivity activity;
    private boolean isSingle;
    private ArrayList<TreeItemViewModel> choicePositions = new ArrayList<>();
    private List<JobBean.ResultsBean> data = new ArrayList<>();

    private ArrayList<TreeModel> choicePositionsValues = new ArrayList<>();
    public final ObservableList<TreeItemViewModel> itemViewModels = new ObservableArrayList<>();
    public final ObservableList<TreeItemViewModel> childItemViewModels = new ObservableArrayList<>();
    public final ObservableField<Drawable> arrow = new ObservableField<>();
    public final ObservableBoolean showLabel = new ObservableBoolean(false);
    public final ObservableBoolean leftVisible = new ObservableBoolean(false);
    public final ObservableBoolean middleVisible = new ObservableBoolean(false);
    public final ObservableBoolean rightVisible = new ObservableBoolean(false);

    public final ObservableField<String> leftText = new ObservableField<>();
    public final ObservableField<String> middleText = new ObservableField<>();
    public final ObservableField<String> rightText = new ObservableField<>();

    public final ObservableField<String> tot alCount = new ObservableField<>();
    public final ObservableField<String> percent = new ObservableField<>("0");

    //三級列表分不同的佈局,分別是case1,2,3
    public final ItemViewSelector<TreeItemViewModel> itemView = new ItemViewSelector<TreeItemViewModel>() {
        @Override
        public void select(ItemView itemView, int position, TreeItemViewModel item) {
            int itemType = item.getTreeModel().isRootNode();
            switch (itemType) {
                case 1:
                    itemView.set(BR.viewModel, R.layout.item_tree_group);
                    break;
                case 2:
                    itemView.set(BR.viewModel, R.layout.item_tree_root);
                    break;
                case 3:
                    itemView.set(BR.viewModel, R.layout.item_tree_leaf);
                    break;
            }

        }

        @Override
        public int viewTypeCount() {
            return 3;
        }
    };

    //初始化上次選中的頁面
    public void setChoicePositions(ArrayList<TreeModel> choicePositions) {
        this.choicePositions.clear();
        ArrayList<TreeItemViewModel> choiceItemViewModels = new ArrayList<>();
        for (TreeModel treeModel : choicePositions) {
            choiceItemViewModels.add(new TreeItemViewModel(activity, treeModel));
        }
        this.choicePositions.addAll(choiceItemViewModels);
        percent.set(choicePositions.size() + "");
        setLabel();
    }

    //初始化資料
    public JobCategoryViewModel(final ChoiceJobCategoryActivity activity) {
        this.activity = activity;
        isSingle = activity.getIntent().getBooleanExtra(EXTRA_SINGLE, false);
        arrow.set(activity.getResources().getDrawable(R.mipmap.icon_down));
        //監聽treeitemviewmodel一級列表的展開
        Messenger.getDefault().register(activity, String.class, new Action1<String>() {
                    @Override
                    public void call(String id) {
                        ArrayList<TreeItemViewModel> removeItems = new ArrayList<>();
                        ArrayList<TreeItemViewModel> removechildItems = new ArrayList<>();
                        for (TreeItemViewModel itemViewModel : itemViewModels) {
                            if (itemViewModel.getTreeModel().getPid().equals(id)) {
                                removeItems.add(itemViewModel);
                            }
                            for (TreeItemViewModel childitemViewModel : itemViewModels) {
                                if (childitemViewModel.getTreeModel().getPid().equals(itemViewModel.getTreeModel().getId())) {
                                    removechildItems.add(childitemViewModel);
                                }
                            }
                        }

                        if (removeItems.size() > 0) {
                            itemViewModels.removeAll(removeItems);
                            itemViewModels.removeAll(removechildItems);
                            activity.initLayout();
                        } else {
                            getGroupNodes(id, "");
                        }
                        removeItems.clear();
                        removechildItems.clear();
                    }
                }

        );
        //監聽treeitemviewmodel 二級列表的展開
        Messenger.getDefault().register(activity, Integer.class, new Action1<Integer>() {
            @Override
            public void call(Integer integer) {
                // ToastUtil.getInstance().show("yijind");
                ArrayList<TreeItemViewModel> removeItems = new ArrayList<>();
                for (TreeItemViewModel itemViewModel : itemViewModels) {
                    if (itemViewModel.getTreeModel().getPid().equals(integer + "")) {
                        removeItems.add(itemViewModel);
                    }
                }

                if (removeItems.size() > 0) {
                    itemViewModels.removeAll(removeItems);
                    activity.initLayout();
                } else {
                    getChildNodes(integer + "", "");
                }
                removeItems.clear();

            }
        });
          //監聽treeitemviewmodel二級和一級 checkbox的選中和移除
        Messenger.getDefault().register(activity, TreeItemViewModel.class, new Action1<TreeItemViewModel>() {
            @Override
            public void call(TreeItemViewModel viewModel) {
                int removeCount = 0;

                if (isSingle) {//單選---->回綁已ok
                    choicePositions.clear();
                    if (itemViewModels != null && itemViewModels.size() > 0) {
                        for (int i = 0; i < itemViewModels.size(); i++) {
                            itemViewModels.get(i).isChoice.set(false);
                        }
                    }
                    viewModel.isChoice.set(true);
                    choicePositions.add(viewModel);
                } else {
                    if (choicePositions != null && choicePositions.size() > 0) {
                        for (int i = 0; i < choicePositions.size(); i++) {
                            TreeItemViewModel item = choicePositions.get(i);
                            if (item.getTreeModel().getId().equals(viewModel.getTreeModel().getId())) {
                                choicePositions.remove(i);//已經選過了,再次點選,則移除,不選中
                                viewModel.isChoice.set(false);
                                removeCount++;
                                break;
                            }
                        }
                    }

                    if (removeCount == 0) {//不是移除操作
                        //多選
                        //數量超過3個
                        if (choicePositions.size() >= 3) {
                            AppDialog.showHintDialog(activity, "最多隻能選擇3個職位");
                            viewModel.isChoice.set(false);
                        } else {
                            //新增到選中集合中
                            choicePositions.add(viewModel);
                            viewModel.isChoice.set(true);
                        }
                    }
                }

                //設定頭上的label
                setLabel();
                setRootNodeSelected();
            }
        });

    }

    private void setRootNodeSelected() {
        for (TreeItemViewModel itemViewModel : itemViewModels) {
            //if (itemViewModel.getTreeModel().isRootNode() == 1) {
            itemViewModel.isChoice.set(false);
            if (choicePositions != null && choicePositions.size() > 0) {
                for (TreeItemViewModel childTreeItemViewModel : choicePositions) {
                    if (itemViewModel.getTreeModel().getId().equals(childTreeItemViewModel.getTreeModel().getId())) {
                        itemViewModel.isChoice.set(true);
                    }
//                        if (itemViewModel.getTreeModel().getId().equals(childTreeItemViewModel.getTreeModel().getId())){
//                            itemViewModel.isChoice.set(true);
//                        }
                }
            }
            //  }
        }
    }

    //設定頭上的label
    private void setLabel() {
        int size = choicePositions.size();
        if (choicePositions.size() > 0) {
            if (!showLabel.get()) {
                arrow.set(activity.getResources().getDrawable(R.mipmap.icon_up));
                showLabel.set(!showLabel.get());
            } else {

            }
        }
        switch (size) {
            case 0: {
                percent.set("0");
                leftVisible.set(false);
                middleVisible.set(false);
                rightVisible.set(false);
            }
            break;
            case 1: {
                percent.set("1");
                leftVisible.set(true);
                leftText.set(choicePositions.get(0).getTreeModel().getName());
                middleVisible.set(false);
                rightVisible.set(false);
            }
            break;
            case 2: {
                percent.set("2");
                leftVisible.set(true);
                middleVisible.set(true);
                leftText.set(choicePositions.get(0).getTreeModel().getName());
                middleText.set(choicePositions.get(1).getTreeModel().getName());
                rightVisible.set(false);
            }
            break;
            case 3: {
                percent.set("3");
                leftVisible.set(true);
                middleVisible.set(true);
                rightVisible.set(true);
                leftText.set(choicePositions.get(0).getTreeModel().getName());
                middleText.set(choicePositions.get(1).getTreeModel().getName());
                rightText.set(choicePositions.get(2).getTreeModel().getName());
            }
            break;
        }
    }

    //獲取第一層資料
    private void getRootNodes() {
        //params.put("grade", "1");
        itemViewModels.clear();
        List<JobBean.ResultsBean> list = new ArrayList<JobBean.ResultsBean>();
        for (JobBean.ResultsBean o : data) {
            if (o.getGrade() == 1) {
                TreeModel treeModel = new TreeModel(o, "0");
                itemViewModels.add(new TreeItemViewModel(activity, treeModel));
                list.add(o);
            }
        }
        if (list.size() == 1) {
            TreeModel treeModel = new TreeModel(list.get(0), "0");
            Messenger.getDefault().sendToTarget(treeModel.getId(), activity);
        }
//
        //setRootNodeSelected();
//
    }

    //獲取第二層資料
    private void getGroupNodes(final String pid, String pname) {

                List<TreeItemViewModel> childItemViewModels=new ArrayList<TreeItemViewModel>();
                for (JobBean.ResultsBean o : data) {
                   if (o.getParentid()==Integer.parseInt(pid)) {
                       TreeModel treeModel = new TreeModel(o, pid, pname);
                       TreeItemViewModel itemViewModel = new TreeItemViewModel(activity, treeModel);
                       itemViewModel.isChoice.set(false);
                       childItemViewModels.add(itemViewModel);
                   }
                }
                String childId = pid;
                int insertIndex = -1;
                for (int i = 0; i < itemViewModels.size(); i++) {
                    if (itemViewModels.get(i).getTreeModel().isRootNode() == 1) {
                        String rootId = itemViewModels.get(i).getTreeModel().getId();
                        if (rootId.equals(childId)) {
                            insertIndex = i + 1;
                        }
                    }
                }
                itemViewModels.addAll(insertIndex, childItemViewModels);
                if (null != choicePositions && choicePositions.size() > 0) {
                    setLabel();
                    setRootNodeSelected();
                }

    }

    //獲取第三層資料
    private void getChildNodes(final String pid, final String pname) {
                ArrayList<TreeItemViewModel> childItemViewModels = new ArrayList<>();
                for (JobBean.ResultsBean o : data) {
                    if (o.getParentid()==Integer.parseInt(pid)) {
                        TreeModel treeModel = new TreeModel( o, "", pname);
                        TreeItemViewModel itemViewModel = new TreeItemViewModel(activity, treeModel);
                        itemViewModel.isChoice.set(false);
                        if (choicePositions != null && choicePositions.size() > 0) {
                            for (TreeItemViewModel selectedItemViewModel : choicePositions) {
                                if (selectedItemViewModel.getTreeModel().getId().equals(treeModel.getId())) {
                                    itemViewModel.isChoice.set(true);
                                }
                            }
                        }

                        childItemViewModels.add(itemViewModel);
                    }
                }

                String childId = pid;
                int insertIndex = -1;
                for (int i = 0; i < itemViewModels.size(); i++) {
                    if (itemViewModels.get(i).getTreeModel().isRootNode() ==2) {
                        String rootId = itemViewModels.get(i).getTreeModel().getId();
                        if (rootId.equals(childId)) {
                            insertIndex = i + 1;
                        }
                    }
                }
                itemViewModels.addAll(insertIndex, childItemViewModels);
                if (null != choicePositions && choicePositions.size() > 0) {
                    setLabel();
                    setRootNodeSelected();
                }
    }


    //左邊點選去除選中
    public final ReplyCommand leftTextClickCommand = new ReplyCommand(new Action0() {
        @Override
        public void call() {
            choicePositions.remove(0);
            setLabel();
            setRootNodeSelected();
        }
    });
    //中間點選去重選中
    public final ReplyCommand middleTextClickCommand = new ReplyCommand(new Action0() {
        @Override
        public void call() {
            choicePositions.remove(1);
            setLabel();
            setRootNodeSelected();
        }
    });
    //右邊點選去除選中
    public final ReplyCommand rightTextClickCommand = new ReplyCommand(new Action0() {
        @Override
        public void call() {
            choicePositions.remove(2);
            setLabel();
            setRootNodeSelected();
        }
    });

    @Override
    public void start(String... args) {
        initJosnData();
        getRootNodes();
    }

    //初始化json資料
    private void initJosnData() {
        try {
            StringBuffer sb = new StringBuffer();
            InputStream is = activity.getAssets().open("job.json");
            int len = -1;
            byte[] buf = new byte[1024];
            while ((len = is.read(buf)) != -1) {
                sb.append(new String(buf, 0, len, "utf-8"));
            }
            is.close();
            Log.d("sdsds", sb.toString() + "hh");
            Gson gson = new Gson();
            JobBean bean= gson.fromJson(sb.toString(),new TypeToken<JobBean>() {}.getType());
            for (JobBean.ResultsBean j:bean.getResults()){
                data.add(j);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

TreeModel 每個item需要用到的資料,其中isRootNode判斷是第幾層

public class TreeModel implements Parcelable {
    private String id;
    private String pid;
    private String name;
    private String parentId;

    private String pname;

    public TreeModel(){}

    public TreeModel(JobBean.ResultsBean resultsBean, String parentId) {
        this.id =resultsBean.getId()+"";
        this.pid = resultsBean.getParentid()+"";
        this.name = resultsBean.getCategoryname();
        this.parentId = parentId;
    }

    public TreeModel(JobBean.ResultsBean resultsBean, String parentId, String pname) {
       this(resultsBean, parentId);
        this.pname = pname;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parentId) {
        this.parentId = parentId;
    }

    public int isRootNode() {
        if (parentId.equals("0")){
            return 1;
        }else if (pid.equals(parentId)){
            return 2;
        }else {
            return 3;
        }
      //  return pid.equals(parentId) ? true : false;
    }
    public boolean isRoot() {

          return pid.equals(parentId) ? true : false;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.id);
        dest.writeString(this.pid);
        dest.writeString(this.name);
        dest.writeString(this.parentId);
        dest.writeString(this.pname);
    }

    protected TreeModel(Parcel in) {
        this.id = in.readString();
        this.pid = in.readString();
        this.name = in.readString();
        this.parentId = in.readString();
        this.pname = in.readString();
    }

    public static final Creator<TreeModel> CREATOR = new Creator<TreeModel>() {
        @Override
        public TreeModel createFromParcel(Parcel source) {
            return new TreeModel(source);
        }

        @Override
        public TreeModel[] newArray(int size) {
            return new TreeModel[size];
        }
    };
}

TreeItemViewModel 繫結 itemview

public class TreeItemViewModel {
    public static final String TAG = TreeItemViewModel.class.getSimpleName();
    private final ChoiceJobCategoryActivity activity;
    private final TreeModel treeModel;
    public final ObservableField<String> name = new ObservableField<>();
    public final ObservableBoolean isChoice = new ObservableBoolean();
    public final ObservableBoolean isUnfold = new ObservableBoolean();

    public TreeItemViewModel(ChoiceJobCategoryActivity activity, TreeModel treeModel) {
        this.treeModel = treeModel;
        this.activity = activity;
        name.set(treeModel.getName());

    }

    public TreeModel getTreeModel() {
        return treeModel;
    }

    //根據treemodel裡面的isRootNode這個引數判斷是第幾層做是否展開的相關操作
    public final ReplyCommand itemClickCommand = new ReplyCommand(new Action0() {
        @Override
        public void call() {
            if (treeModel.isRootNode()==1) {
                isUnfold.set(!isUnfold.get());
                Messenger.getDefault().sendToTarget(treeModel.getId(), activity);
            } else if (treeModel.isRootNode()==2){
                isUnfold.set(!isUnfold.get());
                Messenger.getDefault().sendToTarget(Integer.parseInt(treeModel.getId()), activity);
            }else {
                Messenger.getDefault().sendToTarget(TreeItemViewModel.this, activity);
            }
        }
    });
    //根據treemodel裡面的isRootNode這個引數判斷是第幾層做checkbox是否可以選中的相關操作
    public final ReplyCommand choiceClickCommand = new ReplyCommand(new Action0() {
        @Override
        public void call() {
            if (treeModel.isRootNode()==1) {
            } else if (treeModel.isRootNode()==2){
                Messenger.getDefault().sendToTarget(TreeItemViewModel.this, activity);
             }else {
            }
        }
    });

}

下載程式碼請點選