项目中要求两个红框区域列表滑动时吸顶,头像部分超过四行可上下滑动。
问题①两个区域吸顶实现:这个比较好实现,我是在页面根布局RelativeLayout中写了两个跟吸顶布局一样的View,然后通过监听RecyclerView滑动距离控制RelativeLayout中两个布局的显示和隐藏。代码如下:
productRV.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int[] peopleRegionLoc = new int[2];
peopleRegion.getLocationOnScreen(peopleRegionLoc);
int peopleRegionLocX = peopleRegionLoc[0];
int peopleRegionLocY = peopleRegionLoc[1];
if (isStickTuan == false && peopleRegionLocY <= tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this)) {
isStickTuan = true;
tuanLyStick.setVisibility(View.VISIBLE);
} else if (isStickTuan && peopleRegionLocY > tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this)) {
tuanLyStick.setVisibility(View.INVISIBLE);
isStickTuan = false;
}
int[] grayRegionLoc = new int[2];
grayRegion.getLocationOnScreen(grayRegionLoc);
int grayRegionLocX = grayRegionLoc[0];
int grayRegionLocY = grayRegionLoc[1];
if (isStickTab == false && grayRegionLocY <= tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this) - ScreenUtils.dip2px(HomeZutuanActivity.this, 10)) {
isStickTab = true;
tabLyStick.setVisibility(View.VISIBLE);
} else if (isStickTab && grayRegionLocY > tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this) - ScreenUtils.dip2px(HomeZutuanActivity.this, 10)) {
tabLyStick.setVisibility(View.INVISIBLE);
isStickTab = false;
}
}
});
问题②:RecyclerView嵌套的RecyclerView也要实现可上下滑动。首先我写了最基本的嵌套代码,发现内层RecyclerView根本无法滑动,设置setFocusable也是然并卵。当时第一想法就是先去网上找找有没有类似效果,经过一番搜索以失败而告终。没有办法,只能硬着头皮自己解决滑动冲突。隐隐约约记得之前看过一篇ScrollView嵌套ScrollView的文章(https://mp.weixin.qq.com/s/2-LVR0vTDDLoHQAt7Y4CCw),再次品味突然恍然大悟,自己心里默默地 ao 了一声,原来也不过如此嘛。
解决滑动冲突原理其实就是:当我们想让内层滑动时在onTouchEvent中设置getParent().requestDisallowInterceptTouchEvent(true);这样控制父View不拦截滑动事件,进而让内层获得焦点滑动。当内层RecyclerView滑动到底部了我们要让外层滑动,设置etParent().requestDisallowInterceptTouchEvent(false);并返回false 不消耗事件。具体代码如下:
public class NestRecyclerView extends RecyclerView {
private int lastVisibleItemPosition;
private int firstVisibleItemPosition;
private float mLastY = 0;// 记录上次Y位置
private boolean isTopToBottom = false;
private boolean isBottomToTop = false;
public NestRecyclerView(Context context) {
this(context, null);
}
public NestRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/*@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return super.onInterceptTouchEvent(ev);
}*/
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastY = event.getY();
//不允许父View拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
float nowY = event.getY();
isIntercept(nowY);
if (isBottomToTop||isTopToBottom){
getParent().requestDisallowInterceptTouchEvent(false);
return false;
}else{
getParent().requestDisallowInterceptTouchEvent(true);
}
mLastY = nowY;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return super.onTouchEvent(event);
}
private void isIntercept(float nowY){
isTopToBottom = false;
isBottomToTop = false;
RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
//得到当前界面,最后一个子视图对应的position
lastVisibleItemPosition = ((GridLayoutManager) layoutManager)
.findLastVisibleItemPosition();
//得到当前界面,第一个子视图的position
firstVisibleItemPosition = ((GridLayoutManager) layoutManager)
.findFirstVisibleItemPosition();
}
//得到当前界面可见数据的大小
int visibleItemCount = layoutManager.getChildCount();
//得到RecyclerView对应所有数据的大小
int totalItemCount = layoutManager.getItemCount();
LogUtils.d("nestScrolling","onScrollStateChanged");
if (visibleItemCount>0) {
if (lastVisibleItemPosition == totalItemCount - 1) {
//最后视图对应的position等于总数-1时,说明上一次滑动结束时,触底了
LogUtils.d("nestScrolling", "触底了");
if (NestRecyclerView.this.canScrollVertically(-1) && nowY < mLastY) {
// 不能向上滑动
LogUtils.d("nestScrolling", "不能向上滑动");
isBottomToTop = true;
} else {
LogUtils.d("nestScrolling", "向下滑动");
}
} else if (firstVisibleItemPosition == 0) {
//第一个视图的position等于0,说明上一次滑动结束时,触顶了
LogUtils.d("nestScrolling", "触顶了");
if (NestRecyclerView.this.canScrollVertically(1) && nowY > mLastY) {
// 不能向下滑动
LogUtils.d("nestScrolling", "不能向下滑动");
isTopToBottom = true;
} else {
LogUtils.d("nestScrolling", "向上滑动");
}
}
}
}
}
这个是我重写的RecyclerView解决了嵌套的滑动冲突,喜欢的小伙伴可以直接拿去用。