两个recycleview列表左右联动实现
概述:
在之前的项目中曾经做过电商分类页面左右两个列表联动的实现,当时的做法是左侧列表使用RecycleView,右侧列表使用的是ScrollView,通过onOverScrolled方法来检测右侧列表是否已经到达了顶部继续下拉还是已经到达了底部继续上滑。这种方式肃然也实现了左右两个列表联动的需求,但是体验上还是有继续优化的空间,之后做了一版优化,左右两个列表都是用recycleview来实现。
实现思路:
左右两个recycleview列表,左侧是简单列表,右侧是复杂布局列表,示例如下图:
- 如果每次有次的列表内容长度都能够超过父view的高度,则这种情况很简单,可以单纯依据canScrollVertically接口与onScrolled接口中返回的dy即可确定当前是已经到达顶部在继续下拉,还是已经到达了底部在继续上滑。
- 如果右侧列表内容长度不能超过父view的高度,则第一点的方法就会失效,无法区分以上描述的两种情况。
这里针对这个问题需要额外的添加一个自定义view来确定手指的滑动方向。
public class TouchCheckView extends RelativeLayout {
private float originY,currentY;
public TouchCheckView(Context context) {
this(context, null);
}
public TouchCheckView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
originY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
currentY = ev.getY();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
default:
break;
}
return false;
}
//获取滚动方向,向下为-1,向上为1
public int getScrollDirection() {
if(currentY > originY) {
return -1;
} else {
return 1;
}
}
//获取滚动方向下拉为true,上滑为false
public boolean scrollChangeUp() {
return (currentY > originY) ? true : false;
}
}
这里主要利用了点击事件的传递过程,在时间拦截回调方法onInterceptTouchEvent中将事件的坐标记录下来,之后返回false,交给子view来处理,因为这里只需要知道手指的滑动方向即可,主要的处理逻辑并不在这里。
主页面右侧列表布局如下:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/left_rc"
android:layout_width="@dimen/dp_size_77"
android:layout_height="match_parent"
/>
<com.android.hshq.coupon.view.TouchCheckView
android:id="@+id/touch_check"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/category_main_bg"
android:paddingStart="@dimen/dp_size_13"
android:paddingEnd="@dimen/dp_size_13">
<android.support.v7.widget.RecyclerView
android:id="@+id/right_rc"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
/>
</com.android.hshq.coupon.view.TouchCheckView>
</LinearLayout>
右侧列表RecycleView包含在了TouchCheckView中,这样TouchCheckView就可以检测到recycleview的滑动方向。
这里只列出主要逻辑,所以对一些变量解释如下:
position:记录当前左侧列表选中的item位置
dataList: 左侧列表使用到的数据集合
rightContentInit: 右侧列表是否刚初始化完成
overScrollCount: 当前列表已经滑到最底部或者最顶部的次数
leftTitleClick(int position): 该方法切换左侧列表当前选中状态item的位置
主要处理逻辑如下:
rightRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//只有当前已经停止了滚动才需要处理
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
//第一种情况:recycleView既不能往上滑也不能往下滑了,这就是列表高度不能填满父窗体的时候,
//这里就需要用到之前自定义的view来确定滑动方向
if(!recyclerView.canScrollVertically(1) && !recyclerView.canScrollVertically(-1)) {
//如果是在下拉,并且当前左侧列表选中位置大于0,那就左侧列表选中位置向上切换一个
if(touchCheckView.scrollChangeUp() && position > 0) {
leftTitleClick(position-1);
//如果上滑,并且当前左侧列表选中位置不是最后一个,那就左侧列表选中位置向下切换一个
} else if(!touchCheckView.scrollChangeUp() && position < (dataList.size()-1)) {
leftTitleClick(position+1);
}
return;
}
//如果右侧列表刚初始化完成,并且是下拉,并且左侧列表当前选中item位置大于0,则左侧列表选中位置向上切换一个
if(rightContentInit && touchCheckView.scrollChangeUp() && position > 0) {
leftTitleClick(position-1);
return;
}
//如果右侧列表在其滑动方向上不能再继续滑动了 if(!recyclerView.canScrollVertically(touchCheckView.getScrollDirection())) {
//如果之前已经到达了顶部或者底部
if(overScrollCount >= 1) {
overScrollCount = 0;
//如果是向下滑动,并且左侧选中位置大于0,左侧选中位置向上切换
if(mDy < 0 && position > 0) {
leftTitleClick(position-1);
//如果是向上滑,并且左侧选中位置还没到最末位,左侧选中位置向下切换
} else if(mDy > 0 && position < (dataList.size()-1)) {
leftTitleClick(position+1);
}
} else {
overScrollCount++;
}
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//滑动方向切换了,需要将overScrollCount重置为0
if((mDy > 0 && dy < 0) || (mDy < 0 && dy > 0)) {
overScrollCount = 0;
}
mDy = dy;
//检测到有滑动之后,就应该讲右侧列表初始化状态设置为false
if(mDy != 0) {
rightContentInit = false;
}
}
});
主要逻辑就都罗列出来,且添加了详细注释,其他代码不再列出,最终效果如下:
上一篇: php实现微信企业号支付个人的方法详解
下一篇: C++ 中const修饰虚函数实例详解