Czc'blog

超简单ListView打造的多级展开菜单

最近项目有个需求,需要用到侧边栏的拖出来是一个多级的菜单,但是我们都知道android里面只有二级的expandablelistview这个控件,而且扩展性也不算很好,而项目需求是能够多级展开的,就是有可能扩展到4、5级这样,然后就着手在listview上动文章

效果图

效果图

1.主页

侧边栏用的是v4包的SlidingPaneLayout,里面左右放入fragment填充,但是当右边的fragment内容是viewpager的时候,大家应该都知道,viewpager会和SlidingPaneLayout发生事件冲突,这里我是用网上的方法解决的,大概就是重写SlidingPaneLayout的onInterceptTouchEvent的方法,贴出mainactivity的布局代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<com.example.mrchen.custommultiexpanddemo.ui.PagerEnabledSlidingPaneLayout
android:id="@+id/spl"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/leftfragment"
android:name="com.example.mrchen.custommultiexpanddemo.fragment.LeftFragment"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="start" >
</fragment>
<fragment
android:id="@+id/rightfragment"
android:name="com.example.mrchen.custommultiexpanddemo.fragment.ContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1" >
</fragment>
</com.example.mrchen.custommultiexpanddemo.ui.PagerEnabledSlidingPaneLayout>

2.侧边栏(主要)

LeftFragment里面只是单纯的数据填充,重点在adapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* Created by Mr.chen on 2016/9/30.
* Description 左边栏
*/
public class LeftFragment extends BaseFragment {
private ListView lv;
private List<SideBarItem> list = new ArrayList<SideBarItem>();
private SideBarAdapter adapter;
@Override
public View initView() {
View view = View.inflate(context, R.layout.fragment_left, null);
lv = (ListView) view.findViewById(R.id.lv_sidebar);
return view;
}
/**
* 结构视图(顺序与命名都采用层级式递增)
* -1
* -11
* -12
* -13
*/
@Override
public void initData() {
SideBarItem item1 = new SideBarItem("父级1", 1, R.drawable.icon_mark1);
SideBarItem item2 = new SideBarItem("父级2", 2, R.drawable.icon_mark1);
SideBarItem item21 = new SideBarItem("子级11", 2.1f, R.drawable.icon_mark1);
SideBarItem item22 = new SideBarItem("子级12", 2.2f, R.drawable.icon_mark2);
SideBarItem item23 = new SideBarItem("子级13", 2.3f, R.drawable.icon_mark3);
SideBarItem item221 = new SideBarItem("子级221", 2.21f, R.drawable.icon_mark1);
SideBarItem item222 = new SideBarItem("子级222", 2.22f, R.drawable.icon_mark2);
SideBarItem item223 = new SideBarItem("子级223", 2.23f, R.drawable.icon_mark3);
item22.setParentItem(item2);
item23.setParentItem(item2);
item21.setParentItem(item2);
item222.setParentItem(item22);
item223.setParentItem(item22);
item221.setParentItem(item22);
list.add(item1);
list.add(item2);
list.add(item21);
list.add(item22);
list.add(item23);
list.add(item221);
list.add(item222);
list.add(item223);
adapter = new SideBarAdapter(context, list);
lv.setAdapter(adapter);
}
@Override
public void setListener() {
adapter.setSideBarListener(new SideBarAdapter.SideBarListener() {
@Override
public void onSideBarItemClick(SideBarItem item, int position) {
((MainActivity)context).getContentFragment().setContentText(item);
Toast.makeText(context,"you click " + item.getItemName(),Toast.LENGTH_SHORT).show();
}
});
super.setListener();
}
public void setCurCheckItem(int index){
adapter.setCurCheckItem(index);
}
}

这里面的注释写的算比较清楚,而且源码我也放在github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**
*侧边栏的适配器
*/
public class SideBarAdapter extends BaseAdapter {
private List<SideBarItem> list;
private Context context;
//左边距
private int dp8;
private int dp10;
//临时储存未展开的item
private List<SideBarItem> tempList = new LinkedList<>();
public SideBarAdapter(Context context, List<SideBarItem> list) {
super();
this.context = context;
this.list = list;
dp8 = DensityUtil.dip2px(context, 8);
dp10 = DensityUtil.dip2px(context, 10);
sortItem(list);
removeUnExpandItem(list);
}
/**
* 对侧边栏的数据进行排序
* @param list
*/
private void sortItem(List<SideBarItem> list) {
Collections.sort(list, new Comparator<SideBarItem>() {
@Override
public int compare(SideBarItem lhs, SideBarItem rhs) {
if (lhs.getOrder() - rhs.getOrder() > 0) {
return 1;
} else if (lhs.getOrder() - rhs.getOrder() < 0) {
return -1;
} else {
return 0;
}
}
});
//设置侧边栏的层级和是否选中
for (SideBarItem sideBarItem : list) {
sideBarItem.setLevel(initItemLevel(sideBarItem));
//因为默认只有一个选中,所以一开始进来,全部的没选中,设为false
sideBarItem.setCheck(false);
}
}
/**
* 移除没有展开的item。注意:父亲没有展开,儿子也不给他显示
* @param list
*/
private void removeUnExpandItem(List<SideBarItem> list) {
tempList.clear();
for (SideBarItem sideBarItem : list) {
if (sideBarItem.getParentItem() != null) {
if (!sideBarItem.getParentItem().isExpand()) {
sideBarItem.setExpand(false);
tempList.add(sideBarItem);
}
}
}
list.removeAll(tempList);
}
// 递归设置level
private int initItemLevel(SideBarItem item) {
int level = 1;
if (item.getParentItem() != null) {
item.getParentItem().setHasChild(true);
return (level + initItemLevel(item.getParentItem()));
}
return level;
}
@Override
public int getCount() {
return list.size();
}
@Override
public SideBarItem getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(context, R.layout.adapter_sideritem, null);
holder = new ViewHolder();
holder.tv_item = (TextView) convertView.findViewById(R.id.tv_item);
holder.iv_icon = (ImageView) convertView.findViewById(R.id.iv_item);
holder.iv_arrow = (ImageView) convertView.findViewById(R.id.iv_arrow);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
SideBarItem item = getItem(position);
//根据level,设置padding来达到递进层级的效果
if (item.getLevel() == SideBarItem._First) {
convertView.setPadding(dp10 / 2, dp8, dp8, dp10 / 2);
} else {
convertView.setPadding(2 * dp10 * item.getLevel() - dp10, dp8, dp8, dp10 / 2);
}
//如果有孩子,就有右边的小箭头,没有的话隐藏的
if (item.isHasChild()) {
holder.iv_arrow.setVisibility(View.VISIBLE);
if (item.isExpand()) {
holder.iv_arrow.setBackgroundResource(R.mipmap.inspect_bg_right_open);
}else {
holder.iv_arrow.setBackgroundResource(R.mipmap.inspect_bg_right_close);
}
} else {
holder.iv_arrow.setVisibility(View.GONE);
}
//选中的字体颜色
if (item.isCheck()) {
holder.tv_item.setTextColor(0xFF0000FF);
}else {
holder.tv_item.setTextColor(0xFF000000);
}
holder.iv_icon.setBackgroundResource(item.getResId());
holder.tv_item.setText(item.getItemName());
convertView.setTag(R.id.sidebar, item);
convertView.setTag(R.id.curPosition, position);
convertView.setOnClickListener(clickListener);
return convertView;
}
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
list.addAll(tempList);
sortItem(list);
SideBarItem item = (SideBarItem) v.getTag(R.id.sidebar);
int curPosition = (int) v.getTag(R.id.curPosition);
item.setCheck(!item.isCheck());
item.setExpand(!item.isExpand());
removeUnExpandItem(list);
//设置回调
if (listener!=null) {
listener.onSideBarItemClick(item,curPosition);
}
notifyDataSetChanged();
}
};
class ViewHolder {
TextView tv_item;
ImageView iv_icon;
ImageView iv_arrow;
}
private SideBarListener listener;
public void setSideBarListener(SideBarListener listener){
this.listener = listener;
}
public interface SideBarListener{
void onSideBarItemClick(SideBarItem item, int position);
}
/**
* 设置当前选中的是那个item
* @param index
*/
public void setCurCheckItem(int index) {
list.addAll(tempList);
sortItem(list);
SideBarItem item = getItem(index);
item.setCheck(true);
item.setExpand(true);
removeUnExpandItem(list);
notifyDataSetChanged();
}
}

最后贴上源码,简单不难
https://github.com/behindeye/CustomMultiExpandDemo.git