效果圖
簡介
如上圖展示的內容,篩選條件的功能很常見屏鳍,一般情況如果條件很多勘纯,那么布局文件就會寫的很復雜,這篇文章可以提供一個簡潔的方案钓瞭,布局文件只用一個RecyclerView就可以了驳遵。當然,處理邏輯可能要少費點功夫山涡,不過這些邏輯可以復用堤结,如果有多個地方用到就省很多事了。
代碼分析
先看看Bean類的處理:
數(shù)據(jù)中有幾個必須要添加的屬性
type:用于區(qū)分是標題item還是內容item鸭丛,標題item也可以分很多類竞穷。
choice:標記item是否選中
multiChoice:這一類型標簽是不是多選
allChoice:標簽item是不是全選按鈕(根據(jù)需求調整)
public class GridItemBean {
/**
* type:
* 標題item 自定義
* 內容item 默認為0
*/
private int type;
/**
* 標題(標題item)
*/
private String title;
private String id;
private String name;
/**
* 內容item 是否選擇(內容item)
*/
private boolean choice;
/**
* 是否是多選(標題item)
*/
private boolean multiChoice;
/**
* 是否是全選按鈕(內容item)
*/
private boolean allChoice;
public GridItemBean(int type, String title) {
this.type = type;
this.title = title;
}
public GridItemBean(int type, String title, boolean multiChoice) {
this.type = type;
this.title = title;
this.multiChoice = multiChoice;
}
public GridItemBean(String id, String name) {
this.id = id;
this.name = name;
}
public GridItemBean(String id, String name, boolean allChoice) {
this.id = id;
this.name = name;
this.allChoice = allChoice;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isChoice() {
return choice;
}
public void setChoice(boolean choice) {
this.choice = choice;
}
public boolean isMultiChoice() {
return multiChoice;
}
public void setMultiChoice(boolean multiChoice) {
this.multiChoice = multiChoice;
}
public boolean isAllChoice() {
return allChoice;
}
public void setAllChoice(boolean allChoice) {
this.allChoice = allChoice;
}
@Override
public String toString() {
return "name='" + name + '\'';
}
}
既然布局只是一個RecyclerView,那么邏輯都在adapter中了,首先是adapter的ViewHolder鳞溉,分為兩類瘾带,標題類和內容標簽,根據(jù)bean里面的type來區(qū)分穿挨,這部分沒什么要多說的月弛。
class ChoiceAdapter : ChoiceGridAdapter() {
override fun initData(mData: MutableList<GridItemBean>) {
this.mData = mData
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == 0){
TabHolder(View.inflate(parent?.context , R.layout.item_choice_tab , null))
}else{
TitleHolder(View.inflate(parent?.context , R.layout.item_choice_title , null))
}
}
override fun getItemCount(): Int {
return mData.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (getItemViewType(position) == 0){
(holder as TabHolder).bindData(position)
}else{
(holder as TitleHolder).bindData(position)
}
}
inner class TabHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
fun bindData(position: Int)= with(itemView){
var data = mData[position]
tv_item_tab?.text = data.name
if (data.isChoice){
tv_item_tab?.setBackgroundResource(R.mipmap.search_label_bg_sel02)
}else{
tv_item_tab?.setBackgroundResource(R.mipmap.search_label_bg_nor)
}
setOnClickListener {
if(data.isChoice){
mData[position].isChoice = false
notifyItemChanged(position)
}else{
changeStatus(position)
}
}
}
}
inner class TitleHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
fun bindData(position: Int) = with(itemView){
tv_item_title?.text = mData[position].title
}
}
}
下面是處理邏輯肴盏,寫在了adapter的基類中科盛,方便復用帽衙,布局畢竟是都不一樣的,但是邏輯可以通用贞绵,具體要按項目需求來定厉萝,靈活修改。
abstract class ChoiceGridAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var mData: MutableList<GridItemBean> = mutableListOf()
abstract fun initData(mData: MutableList<GridItemBean>)
override fun getItemViewType(position: Int): Int {
return mData[position].type
}
/**
* 修改選擇條目
*/
fun changeStatus(position: Int){
var first = 0 // 同類型的第一條數(shù)據(jù)位置
var last = mData.size // 同類型的最后一條數(shù)據(jù)位置
for(index in position downTo 0){
if (mData[index].type != 0){
first = index
break
}
}
for (index in (position + 1) until mData.size){
if (mData[index].type != 0){
last = index
break
}
}
if (last > first){
if (mData[first].isMultiChoice){
// 是多選
if (mData[position].isAllChoice){ // 全選按鈕
for (index in first until last){
mData[index].isChoice = false
}
mData[position].isChoice = true
notifyDataSetChanged()
}else{
for (index in first until last){
// 重置全選按鈕
if (mData[index].isAllChoice){
mData[index].isChoice = false
notifyItemChanged(index)
break
}
}
mData[position].isChoice = true
notifyItemChanged(position)
}
}else{
// 是單選
var currentIndex = 0
for (index in first until last){
// 查找當前選擇的位置
if (mData[index].isChoice){
mData[index].isChoice = false
currentIndex = index
break
}
}
notifyItemChanged(currentIndex)
mData[position].isChoice = true
notifyItemChanged(position)
}
}
}
/**
* 查找選擇的條目
*/
fun getChoiceItem(type: Int): GridItemBean?{
var first = 0 // 同類型的第一條數(shù)據(jù)位置
var last = mData.size // 同類型的最后一條數(shù)據(jù)位置
for (index in mData.indices){
if (mData[index].type == type){
first = index
break
}
}
for (index in (first + 1) until mData.size){
if (mData[index].type != 0){
last = index
break
}
}
for (index in first until last){
if (mData[index].isChoice){
return mData[index]
break
}
}
return null
}
/**
* 查找多選選擇的條目
*/
fun getMultiChoiceItem(type: Int): MutableList<GridItemBean>?{
var multiData = mutableListOf<GridItemBean>()
var first = 0 // 同類型的第一條數(shù)據(jù)位置
var last = mData.size // 同類型的最后一條數(shù)據(jù)位置
for (index in mData.indices){
if (mData[index].type == type){
first = index
break
}
}
for (index in (first + 1) until mData.size){
if (mData[index].type != 0){
last = index
break
}
}
var allChoice = false
for (index in first until last){
// 判斷是否全選
if (mData[index].isAllChoice){
allChoice = mData[index].isChoice
break
}
}
if (allChoice){
// 全選
for (index in first until last){
if (mData[index].type == 0 && !mData[index].isAllChoice){
multiData.add(mData[index])
}
}
}else{
// 非全選
for (index in first until last){
if (mData[index].isChoice){
multiData.add(mData[index])
}
}
}
return multiData
}
/**
* 重置
*/
fun clearChoice(){
for (index in mData.indices){
mData[index].isChoice = false
notifyDataSetChanged()
}
}
}
changeStatus()方法是用來更新item選中的榨崩,更新的時候谴垫,要先查出當前選的這個標簽的所有同類型的坐標,第一個和最后一個母蛛,邏輯就是查上一個標題類和下一個標題類翩剪,中間所有的標簽都是這個類型的,然后根據(jù)是多選還是單選彩郊,更新標簽的choice屬性前弯。
getChoiceItem()和getMultiChoiceItem()是獲取單選或者多選選中的標簽,也是要先獲取同類標簽的第一個和最后一個位置秫逝,遍歷獲取恕出。
最后看看activity中數(shù)據(jù)的準備(根據(jù)需求調整)
override fun initData() {
mData.add(GridItemBean(1, "類型(多選)" , true))
mData.add(GridItemBean("1" , "全部" , true))
mData.add(GridItemBean("2" , "11"))
mData.add(GridItemBean("3" , "12"))
mData.add(GridItemBean("4" , "13"))
mData.add(GridItemBean("4" , "14"))
mData.add(GridItemBean(2 , "標準(單選)"))
mData.add(GridItemBean("5" , "20"))
mData.add(GridItemBean("6" , "21"))
mData.add(GridItemBean("7" , "22"))
mData.add(GridItemBean("8" , "23"))
mData.add(GridItemBean("8" , "24"))
mData.add(GridItemBean(3 , "屬性(多選)", true))
mData.add(GridItemBean("5" , "30"))
mData.add(GridItemBean("6" , "31"))
mData.add(GridItemBean("7" , "32"))
mData.add(GridItemBean("8" , "33"))
mData.add(GridItemBean("8" , "34"))
mAdapter = ChoiceAdapter()
mAdapter?.initData(mData)
RecyclerViewUtil.initGrid(this, recycler_grid , mAdapter,4)
var layoutManager : GridLayoutManager = recycler_grid?.layoutManager as GridLayoutManager
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup(){
override fun getSpanSize(position: Int): Int {
var type = mAdapter?.getItemViewType(position)
return if (type == 0) 1 else 4
}
}
}
fun getData(view: View){
var data1 = mAdapter?.getMultiChoiceItem(1)
LogUtil.logShow(data1?.toString())
var data2 = mAdapter?.getChoiceItem(2)
LogUtil.logShow(data2?.toString())
var data3 = mAdapter?.getMultiChoiceItem(3)
LogUtil.logShow(data3?.toString())
tv_show?.text = "data1 = " + data1.toString() + "\ndata2 = " + data2.toString() + "\ndata3 = " + data3.toString()
}
fun backData(view: View){
mAdapter?.clearChoice()
tv_show?.text = ""
}