android-Data Binding+recycleview打造二三級都可以選擇的三級列表
阿新 • • 發佈:2018-11-14
效果圖
這是前段時間做得一個專案需求,要求能夠選擇選擇第二級和第三級的一個三級列表,話不多說了,看程式碼吧
一、專案配置
由於這個專案早期的框架用的是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 {
}
}
});
}