最近项目有个需求,需要用到侧边栏的拖出来是一个多级的菜单,但是我们都知道android里面只有二级的expandablelistview这个控件,而且扩展性也不算很好,而项目需求是能够多级展开的,就是有可能扩展到4、5级这样,然后就着手在listview上动文章
效果图
1.主页
侧边栏用的是v4包的SlidingPaneLayout,里面左右放入fragment填充,但是当右边的fragment内容是viewpager的时候,大家应该都知道,viewpager会和SlidingPaneLayout发生事件冲突,这里我是用网上的方法解决的,大概就是重写SlidingPaneLayout的onInterceptTouchEvent的方法,贴出mainactivity的布局代码
<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
/**
* 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
/**
*侧边栏的适配器
*/
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