如何实现Expandable ListView同一父组子项点击后滑动切换功能
功能实现方案
问题根因说明
你之前适配失败的核心原因是ExpandableListView和ViewPager同属可滑动控件,同布局共存时会触发原生的触摸事件冲突,导致其中一方滑动无响应。
推荐实现方案(无滑动冲突,适配成本最低)
不要将ViewPager嵌入ExpandableListView的子项布局,改用分层布局结构:
- 布局根节点使用
FrameLayout,下层放置ExpandableListView,上层放置ViewPager,ViewPager默认设置android:visibility="gone"隐藏 - 给ExpandableListView设置
OnChildClickListener,点击子项时执行以下逻辑:- 获取当前点击的父组索引、子项索引
- 从你的业务数据源中取出该父组下的所有子项数据集合
- 初始化ViewPager的适配器,将上述子项数据集合传入适配器
- 调用
viewPager.setCurrentItem(子项索引, false)直接定位到用户点击的子项内容 - 将ViewPager设置为
VISIBLE,可搭配淡入动画优化过渡效果
- 回退逻辑处理:重写Activity的
onBackPressed方法,若ViewPager处于可见状态,优先隐藏ViewPager回到列表页,否则走正常回退逻辑
该方案两个控件不同时响应用户操作,完全规避滑动冲突,同时满足点击子项后滑动切换同组相邻子项的需求。
替代方案(ViewPager嵌入子项布局的场景)
如果你的业务要求ViewPager必须放在ExpandableListView的展开子项内,则自定义ViewPager处理触摸事件分发即可解决冲突:
自定义仅响应水平滑动的ViewPager,代码如下:
public class HorizontalOnlyViewPager extends ViewPager { private float downX, downY; private final int touchSlop; public HorizontalOnlyViewPager(Context context) { super(context); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } public HorizontalOnlyViewPager(Context context, AttributeSet attrs) { super(context, attrs); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: downX = ev.getX(); downY = ev.getY(); getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(ev.getX() - downX); float dy = Math.abs(ev.getY() - downY); if (dx > dy && dx > touchSlop) { // 水平滑动场景,由当前ViewPager处理事件 getParent().requestDisallowInterceptTouchEvent(true); } else { // 垂直滑动场景,交给父列表处理滚动 getParent().requestDisallowInterceptTouchEvent(false); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: getParent().requestDisallowInterceptTouchEvent(false); break; } return super.onInterceptTouchEvent(ev); } }
布局文件中将原生ViewPager替换为上述自定义的HorizontalOnlyViewPager即可正常适配。
优化建议
原生ExpandableListView属于已淘汰的老控件,如果你当前项目使用AndroidX,建议改用RecyclerView实现折叠列表,扩展性和适配性更高;如果子项数量较多,可改用ViewPager2搭配FragmentStateAdapter实现,内存占用更低。
内容的提问来源于stack exchange,提问作者Nwadinigwe Michael
相关产品推荐
相关产品推荐

