简要说明
V1版本的地址 之前写过一篇,V1版本的思路,但是感觉写的还不是很好。很早之前看到了一篇写的很好的文章,文章地址 Android嵌套滑动机制实战演练 我就在想是否可以结合他的再来改改,于是就有了V2版本 嘻嘻。
github 地址 里面的MainActivity 是V1的代码,ThiredActivity 是V2代码
开发的时候遇到的问题
1、外层是RecyclerView且含有多type,里面其中一个type里面含有recyclerview。在处理滑动过程中发现,无论滑动的是外层recyclerview,还是里层的recyclerview,startNestedScroll 都会被调用(先调用父),但是 dispatchNestedPreScroll 只有最外层的才会被调用。问题就在这里,如果要实现嵌套滑动,需要内部的 dispatchNestedPreScroll 调用才能正常执行逻辑
xml简单结构图.jpg
解决问题
既然 子recyclerview里面的 dispatchNestedPreScroll 没办法调用,我们就要换个思路来解决问题
简单结构图.jpg
这里比较重要的是 NestedFrameLayout,它 implements NestedScrollingParent3 ,我们需要在 onNestedPreScroll 里面进行处理,在处理的时候,我们需要注意 MyThiredBottomLinLerLayout.getTop 是否为0,如果是0,我们就只能够滚动 childRecyclerView,否则就滚动 rootRecyclerView
@Override
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
if (target instanceof RecyclerView) {
if (dy > 0) {//手指向上
if (bottomThiredLinLerLayout != null) {
if (bottomThiredLinLerLayout.getTop() != 0) { 只能滚动父的recyclerView
rootRecyclerView.scrollBy(0, dy);
} else if (bottomThiredLinLerLayout.getTop() == 0) { 我们只能滚动childRecyclerview
if (childRecyclerView != null) {
bottomThiredLinLerLayout.toDoNestedPreScroll(dy); 这里是处理标题隐藏和显示的地方
childRecyclerView.scrollBy(0, dy);
consumed[1] = dy;
}
}
}else {
rootRecyclerView.scrollBy(0, dy);
}
}
if (dy < 0) {//手指向下
if (bottomThiredLinLerLayout!=null){
if (bottomThiredLinLerLayout.getTop() != 0) {
rootRecyclerView.scrollBy(0, dy);
consumed[1] = dy;
} else if (bottomThiredLinLerLayout.getTop() == 0) {
if (childRecyclerView != null) {
bottomThiredLinLerLayout.toDoNestedPreScroll(dy);
if (childRecyclerView.canScrollVertically(dy)) {
childRecyclerView.scrollBy(0, dy);
consumed[1] = dy;
} else {
rootRecyclerView.scrollBy(0, dy);
}
}
}
}else {
rootRecyclerView.scrollBy(0, dy);
}
}
}
}
MyThiredBottomLinLerLayout 这个也是一个很重要的类,在V1版本的时候,我们 implements NestedScrollingParent3 接口,但是!!!如果根布局是RecyclerView 里面的一个Type为 RecyclerView ,我们滚动childRecyclerView,虽然会触发 onStartNestedScroll,但是不会触发 dispatchNestedPreScroll ,初步怀疑是因为根RecyclerView return fase 导致的。最先调用 dispatchNestedPreScroll 是根recyclerView
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
@Nullable int[] offsetInWindow, @NestedScrollType int type) {
if (isNestedScrollingEnabled()) {
final ViewParent parent = getNestedScrollingParentForType(type); 这里返回的parent 为 null ,该行意思为,是否含有嵌套的Parent
if (parent == null) {
return false;
}
if (dx != 0 || dy != 0) {
int startX = 0;
int startY = 0;
if (offsetInWindow != null) {
mView.getLocationInWindow(offsetInWindow);
startX = offsetInWindow[0];
startY = offsetInWindow[1];
}
if (consumed == null) {
consumed = getTempNestedScrollConsumed();
}
consumed[0] = 0;
consumed[1] = 0;
ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);
.... 省略
}
所以这里我将 MyThiredBottomLinLerLayout 里面的 NestedScrollingParent3 实现去掉,直接换成了 toDoNestedPreScroll 方法
public void toDoNestedPreScroll(int dy){
if (titleDescLayout == null) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view.getId() == R.id.ctl_thired_layout) {
titleDescLayout = view.findViewById(R.id.ll_thired_title_desc);
break;
}
}
}
if (dy > 0) {//手指向上
if (isDescExOpen && !animatorIsRunning) {
animatorIsRunning = true;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.1f);
valueAnimator.setDuration(200);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) titleDescLayout.getLayoutParams();
layoutParams.height = (int) (getTitleDescHeight() * value);
titleDescLayout.setLayoutParams(layoutParams);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isDescExOpen = false;
animatorIsRunning = false;
}
});
valueAnimator.start();
}
}
if (dy < 0) {//手指向下
if (!isDescExOpen && !animatorIsRunning && !currentRecyclerView.canScrollVertically(dy)) {
animatorIsRunning = true;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.1f, 1.0f);
valueAnimator.setDuration(200);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) titleDescLayout.getLayoutParams();
layoutParams.height = (int) (getTitleDescHeight() * value);
titleDescLayout.setLayoutParams(layoutParams);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isDescExOpen = true;
animatorIsRunning = false;
}
});
valueAnimator.start();
}
}
}
网友评论