Behavior搭建多RecyclerView的复杂界面

2024-05-10 05:58

本文主要是介绍Behavior搭建多RecyclerView的复杂界面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Behavior搭建多RecycleView的复杂界面之MultiRecycleContainer

  • 开发意图
  • 开发思路
  • demo视图
  • 代码部分
    • 1.自定义RecyclerView容器
    • 2.Behavior部分
  • 使用部分
    • 1.xml布局
    • 2.java部分
  • 遗留
  • 我的项目

开发意图

Android原生开发多个RecyclerView的复杂界,如淘宝首页这样的界面。不可避免的遇到滑动冲突的问题,官方为我们提供了NestedScrollView可以很完美的解决滑动问题。这里记录一下在没有了解NestedScrollView源码的情况下,自己采用behavior的解决思路。

在这里插入图片描述

开发思路

1.自定义RecyclerView容器(只包含一个RecyclerView可以添加其他布局)
2.把自定义容器部署到CoordinatorLayout内
2.使用Behavior统一管理自定义容器(位置及滑动事件)

demo视图

在这里插入图片描述

代码部分

1.自定义RecyclerView容器

package cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.RecyclerView;import cn.demomaster.huan.quickdeveloplibrary.util.QDLogger;@CoordinatorLayout.DefaultBehavior(MultiRecycleBehavior.class)
public class MultiRecycleContainer extends FrameLayout {private RecyclerView recyclerView;public MultiRecycleContainer(@NonNull Context context) {super(context);init(null);}public MultiRecycleContainer(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(attrs);}public MultiRecycleContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(attrs);}@Overrideprotected boolean addViewInLayout(View child, int index, ViewGroup.LayoutParams params) {return super.addViewInLayout(child, index, params);}private void init(AttributeSet attrs) {getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {getViewTreeObserver().removeOnGlobalLayoutListener(this);findRecyclerView(MultiRecycleContainer.this);}});}/*** 查找唯一的一个RecyclerView* @param child*/private void findRecyclerView(View child) {if (child instanceof ViewGroup && !(child instanceof RecyclerView)) {for (int i = 0; i < ((ViewGroup) child).getChildCount(); i++) {View v = ((ViewGroup) child).getChildAt(i);findRecyclerView(v);}} else if (child instanceof RecyclerView) {recyclerView = (RecyclerView) child;}}@Overridepublic boolean onTouchEvent(MotionEvent event) {QDLogger.d("onTouchEvent=" + event);/*** 把自身及其他子空间的触摸事件传递给recyclerView,其他控件如果不使用触摸滑动可以在ontouch中消耗掉即可*/if (recyclerView != null) {recyclerView.dispatchTouchEvent(event);}return true;//return super.onTouchEvent(event);}private int mHeaderViewHeight;private int mRecycleViewHeight;private int mViewHeight;@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {findRecyclerView(this);if (recyclerView == null) return;QDLogger.d("onSizeChanged w=" + w + ",h=" + h + ",oldw=" + oldw + ",oldh=" + oldh);if (w != oldw || h != oldh) {// mHeaderViewHeight = findViewById(R.id.header).getMeasuredHeight();mRecycleViewHeight = recyclerView.getMeasuredHeight();mViewHeight = mHeaderViewHeight + mRecycleViewHeight;}QDLogger.d("mHeaderViewHeight=" + mHeaderViewHeight);}public int getHeaderViewHeight() {return mHeaderViewHeight;}public int getViewHeight() {return mViewHeight;}
}

MultiRecycleContainer部分和RecyclerView为一对一的关系,主要负责管理一个recyclerView并且可以添加其他自定义的布局

2.Behavior部分

package cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout;import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.OverScroller;import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.MotionEventCompat;
import androidx.core.view.VelocityTrackerCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;import cn.demomaster.huan.quickdeveloplibrary.util.QDLogger;public class MultiRecycleBehavior extends CoordinatorLayout.Behavior<MultiRecycleContainer> {CoordinatorLayout parent;@Overridepublic boolean onLayoutChild(@NonNull CoordinatorLayout parent, @NonNull MultiRecycleContainer child, int layoutDirection) {QDLogger.d("onLayoutChild");parent.onLayoutChild(child, layoutDirection);//获取上一个MultiRecycleContainer容器MultiRecycleContainer previous = getPreviousChild(parent, child);if (previous == null) {//为空说明child的position=0int offset = child.getTop();QDLogger.d("SlidingBehavior", child.getId() + "offsetTopAndBottom=" + offset + ", top=" + child.getTop() + ",y=" + child.getY());} else {//获取上一个MultiRecycleContainer容器,来确定当前child的位置 (当前child的位置为,上一个的top+上一个的height)int offset = previous.getTop() + previous.getHeight();child.offsetTopAndBottom(offset);}return true;}/*** 获取MultiRecycleContainer列表中的上一个* @param parent  CoordinatorLayout父容器* @param child  当前MultiRecycleContainer* @return*/private MultiRecycleContainer getPreviousChild(CoordinatorLayout parent, MultiRecycleContainer child) {int cartindex = parent.indexOfChild(child);for (int i = cartindex - 1; i >= 0; i--) {View v = parent.getChildAt(i);if (v instanceof MultiRecycleContainer) {return (MultiRecycleContainer) v;}}return null;}boolean isVerticalScroll;//是否是垂直滚动@Overridepublic boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull MultiRecycleContainer child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {QDLogger.d("onStartNestedScroll axes=" + axes + ",target=" + target.getClass().getName());this.parent = coordinatorLayout;if (!isInital) {//初始化惯性滚动init(parent);}boolean isVertical = (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;isVerticalScroll = isVertical && child == directTargetChild;//返回true则子view不在进行滚动return isVerticalScroll;}@Overridepublic boolean onNestedPreFling(@NonNull CoordinatorLayout parent, @NonNull MultiRecycleContainer child, @NonNull View target, float velocityX, float velocityY) {//int shift = scroll(parent, child, (int) velocityY);// return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);return false;}@Overridepublic boolean onNestedFling(@NonNull CoordinatorLayout parent, @NonNull MultiRecycleContainer child, @NonNull View target, float velocityX, float velocityY, boolean consumed) {QDLogger.d("onNestedFling...");//return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);scroll(parent, child, consumed ? 0 : (int) velocityY);scrollParent(parent, child, null, consumed ? 0 : (int) velocityY);return false;}@Overridepublic void onNestedPreScroll(@NonNull CoordinatorLayout parent, @NonNull MultiRecycleContainer child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {QDLogger.d("dy=" + dy + ",consumed x=" + consumed[0] + ",y=" + consumed[1]);//dy>0上推,dy<0下拉boolean canScrollDown = target.canScrollVertically(-1);//的值表示是否能向下滚动boolean isToped = !canScrollDown;//表示是否已经滚动到顶部boolean canScrollUp = ViewCompat.canScrollVertically(target, 1);//的值表示是否能向上滚动boolean isBottomed = !canScrollUp;//表示已经滚动到底部QDLogger.d("isToped=" + isToped + ",isBottomed=" + isBottomed + ",child.getTop()=" + child.getTop());if (child.getTop() == 0 && ((dy > 0 && canScrollUp) || (dy < 0 && canScrollDown))) {consumed[1] = scrollChild(parent, child, target, dy);} else {consumed[1] = scrollParent(parent, child, target, dy);}//super.onNestedPreScroll(parent, child, target, dx, dy, consumed, type);}/*** 优先父view 消耗** @param parent* @param target* @param dy* @return*/private int scrollParent(CoordinatorLayout parent, MultiRecycleContainer child, View target, int dy) {int py = 0;QDLogger.d("获取下一个可滚动的视图");//1.获取下一个可滚动的视图if (dy > 0) {//上推QDLogger.d("上推");MultiRecycleContainer upper = getUpperChild(parent);QDLogger.d("获取下一个可上推的视图:" + upper);if (upper == null) {py = dy;} else {QDLogger.d("获取下一个可上推的视图:" + upper + ",dy=" + dy + ",upper.getTop()=" + upper.getTop());py = Math.min(upper.getTop(), dy);}} else {//下拉QDLogger.d("下拉");MultiRecycleContainer downer = getDownerChild(parent);//下一个QDLogger.d("获取下一个可下拉的视图:" + downer);if (downer == null) {py = dy;} else {QDLogger.d("获取下一个可下拉的视图dy=" + dy + ",downer.getTop()=" + downer.getTop());py = Math.max(downer.getTop(), dy);}}//2.scrollPrentscroll(parent, child, py);return py;}/*** 获取下一个即将要出现的可下拉滚动的控件** @param parent* @return*/private MultiRecycleContainer getDownerChild(CoordinatorLayout parent) {MultiRecycleContainer current = getCurrentChild(parent);int index = parent.indexOfChild(current);for (int i = index; i > 0; i--) {View v = parent.getChildAt(i);if (v instanceof MultiRecycleContainer) {boolean canScrollDown = (getChildRecyclerView((ViewGroup) v)).canScrollVertically(-1);//的值表示是否能向下滚动if (canScrollDown) {//下拉return (MultiRecycleContainer) v;}}}return null;}/*** 获取下一个即将要出现的可上推滚动的控件** @param parent* @return*/private MultiRecycleContainer getUpperChild(CoordinatorLayout parent) {MultiRecycleContainer current = getCurrentChild(parent);int index = parent.indexOfChild(current);W:for (int i = index; i < parent.getChildCount(); i++) {View v = parent.getChildAt(i);if (v instanceof MultiRecycleContainer) {if (getChildRecyclerView((ViewGroup) v) == null) continue W;boolean canScrollUp = ViewCompat.canScrollVertically(getChildRecyclerView((ViewGroup) v), 1);//的值表示是否能向上滚动if (canScrollUp) {//可上推return (MultiRecycleContainer) v;}}}return null;}/*** 获取child中的第一个recycleView,所以每个StackSlidingLayout中只能放一个recycleView** @param v* @return*/private RecyclerView getChildRecyclerView(ViewGroup v) {for (int i = 0; i < v.getChildCount(); i++) {if (v.getChildAt(i) instanceof RecyclerView) {return (RecyclerView) v.getChildAt(i);}if (v.getChildAt(i) instanceof ViewGroup) {RecyclerView recyclerView = findRecycleView((ViewGroup) v.getChildAt(i));if (recyclerView != null) {return recyclerView;}}}return null;}/*** 获取当前子容器中的recycle,注意每个容器中只存放一个recyclerView* @param viewGroup* @return*/private RecyclerView findRecycleView(ViewGroup viewGroup) {for (int i = 0; i < viewGroup.getChildCount(); i++) {if (viewGroup.getChildAt(i) instanceof RecyclerView) {return (RecyclerView) viewGroup.getChildAt(i);}if (viewGroup.getChildAt(i) instanceof ViewGroup) {RecyclerView recyclerView = findRecycleView((ViewGroup) viewGroup.getChildAt(i));if (recyclerView != null) {return recyclerView;}}}return null;}/*** 优先子view滚动** @param parent* @param target* @param dy* @return*/private int scrollChild(CoordinatorLayout parent, MultiRecycleContainer child, View target, int dy) {//1.优先parent滑动//2.寻找到可以滚动的下一个childreturn 0;}@Overridepublic void onNestedScroll(@NonNull CoordinatorLayout parent, @NonNull MultiRecycleContainer child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, @NonNull int[] consumed) {QDLogger.d("onNestedScroll...");//dy>0上推,dy<0下拉boolean canScrollDown = target.canScrollVertically(-1);//的值表示是否能向下滚动boolean isToped = !canScrollDown;//表示是否已经滚动到顶部boolean canScrollUp = ViewCompat.canScrollVertically(target, 1);//的值表示是否能向上滚动boolean isBottomed = !canScrollUp;//表示已经滚动到底部QDLogger.d("isToped=" + isToped + ",isBottomed=" + isBottomed + ",child.getTop()=" + child.getTop());if (child.getTop() == 0 && ((dyUnconsumed > 0 && canScrollUp) || (dyUnconsumed < 0 && canScrollDown))) {consumed[1] = scrollChild(parent, child, target, dyUnconsumed);} else {consumed[1] = scrollParent(parent, child, target, dyUnconsumed);}}private int scroll(CoordinatorLayout parent, MultiRecycleContainer child, int dy) {//1.k控制自己的移动int initialOffset = child.getTop();MultiRecycleContainer firstchild = getFirstChild(parent);MultiRecycleContainer lastchild = getLastChild(parent);//dy>0上推,dy<0下拉int top = firstchild.getTop();int bottom = lastchild.getBottom() - parent.getHeight();QDLogger.d("height=" + parent.getHeight() + ",lastchild.getBottom()=" + lastchild.getBottom() + ",firstchild.getTop()=" + firstchild.getTop());QDLogger.d("dy=" + dy + ",min=" + top + ",max=" + top + ",initialOffset - dy=" + (initialOffset - dy));int offset = 0;//= clamp(initialOffset - dy,top ,top)-initialOffset;//offset = 目标值-当前值if (dy > 0) {offset = -Math.min(dy, bottom);} else if (dy < 0) {offset = -Math.max(dy, top);}child.offsetTopAndBottom(offset);moveOther(parent, child, offset);return dy - offset;//滑动方向}/*** 获取下一个MultiRecycleContainer* @param parent* @param child* @return*/private MultiRecycleContainer getNextChild(CoordinatorLayout parent, MultiRecycleContainer child) {int cartindex = parent.indexOfChild(child);for (int i = cartindex + 1; i < parent.getChildCount(); i++) {View v = parent.getChildAt(i);if (v instanceof MultiRecycleContainer) {return (MultiRecycleContainer) v;}}return null;}/*** 获取第一个MultiRecycleContainer* @param parent* @return*/private MultiRecycleContainer getFirstChild(CoordinatorLayout parent) {MultiRecycleContainer firstchild = null;for (int i = 0; i < parent.getChildCount(); i++) {View view = parent.getChildAt(i);if (view instanceof MultiRecycleContainer) {firstchild = (MultiRecycleContainer) view;return firstchild;}}return firstchild;}/*** 获取当前MultiRecycleContainer* @param parent* @return*/private MultiRecycleContainer getCurrentChild(CoordinatorLayout parent) {MultiRecycleContainer current = null;for (int i = 0; i < parent.getChildCount(); i++) {View view = parent.getChildAt(i);if (view.getTop() >= 0) {return (MultiRecycleContainer) view;}}return current;}/*** 获取最后一个MultiRecycleContainer* @param parent* @return*/private MultiRecycleContainer getLastChild(CoordinatorLayout parent) {MultiRecycleContainer lastchild = null;for (int i = parent.getChildCount() - 1; i >= 0; i--) {View view = parent.getChildAt(i);if (view instanceof MultiRecycleContainer) {lastchild = (MultiRecycleContainer) view;return lastchild;}}return lastchild;}/*** 获取CoordinatorLayout所有子view视图高度* @param parent* @return*/private int getAllChildHeight(CoordinatorLayout parent) {int height = 0;for (int i = 0; i < parent.getChildCount(); i++) {height += parent.getChildAt(i).getHeight();}return height;}/*** 移动其他平级的MultiRecycleContainer* @param parent* @param child* @param offset*/private void moveOther(CoordinatorLayout parent, MultiRecycleContainer child, int offset) {MultiRecycleContainer current = child;MultiRecycleContainer above = getPreviousChild(parent, current);while (above != null) {int offset_c = current.getTop() - above.getHeight() - above.getTop();above.offsetTopAndBottom(offset_c);current = above;above = getPreviousChild(parent, current);}current = child;MultiRecycleContainer below = getNextChild(parent, current);while (below != null) {int offset_c = current.getTop() + current.getHeight() - below.getTop();below.offsetTopAndBottom(offset_c);current = below;below = getNextChild(parent, current);}}/****************   以下参考网上的惯性滚动   效果还不是很好     ****************************************************************/private boolean isInital;private void init(View view) {isInital = true;this.mContext = view.getContext();mViewFlinger = new ViewFlinger(mContext, view);final ViewConfiguration vc = ViewConfiguration.get(mContext);mTouchSlop = vc.getScaledTouchSlop();mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();DisplayMetrics metric = mContext.getResources().getDisplayMetrics();SCREEN_WIDTH = metric.widthPixels;SCREEN_HEIGHT = metric.heightPixels;}private Context mContext;private int SCREEN_WIDTH = 0;private int SCREEN_HEIGHT = 0;private int mWidth = 0;private int mHeight = 0;private static final int INVALID_POINTER = -1;public static final int SCROLL_STATE_IDLE = 0;public static final int SCROLL_STATE_DRAGGING = 1;public static final int SCROLL_STATE_SETTLING = 2;private int mScrollState = SCROLL_STATE_IDLE;private int mScrollPointerId = INVALID_POINTER;private int mLastTouchY;private int mTouchSlop;private int mMinFlingVelocity;private int mMaxFlingVelocity;private ViewFlinger mViewFlinger;private VelocityTracker mVelocityTracker;//滑动速度跟踪器@Overridepublic boolean onTouchEvent(@NonNull CoordinatorLayout parent, @NonNull MultiRecycleContainer child, @NonNull MotionEvent event) {if (!isInital) {init(parent);}if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}boolean eventAddedToVelocityTracker = false;final int action = MotionEventCompat.getActionMasked(event);final int actionIndex = MotionEventCompat.getActionIndex(event);final MotionEvent vtev = MotionEvent.obtain(event);switch (action) {case MotionEvent.ACTION_DOWN: {setScrollState(SCROLL_STATE_IDLE);mScrollPointerId = event.getPointerId(0);mLastTouchY = (int) (event.getY() + 0.5f);break;}case MotionEventCompat.ACTION_POINTER_DOWN: {mScrollPointerId = event.getPointerId(actionIndex);mLastTouchY = (int) (event.getY(actionIndex) + 0.5f);break;}case MotionEvent.ACTION_MOVE: {final int index = event.findPointerIndex(mScrollPointerId);if (index < 0) {Log.e("zhufeng", "Error processing scroll; pointer index for id " + mScrollPointerId + " not found. Did any MotionEvents get skipped?");return false;}final int y = (int) (event.getY(index) + 0.5f);int dy = mLastTouchY - y;if (mScrollState != SCROLL_STATE_DRAGGING) {boolean startScroll = false;if (Math.abs(dy) > mTouchSlop) {if (dy > 0) {dy -= mTouchSlop;} else {dy += mTouchSlop;}startScroll = true;}if (startScroll) {setScrollState(SCROLL_STATE_DRAGGING);}}if (mScrollState == SCROLL_STATE_DRAGGING) {mLastTouchY = y;constrainScrollBy(dy);}break;}case MotionEventCompat.ACTION_POINTER_UP: {if (event.getPointerId(actionIndex) == mScrollPointerId) {// Pick a new pointer to pick up the slack.final int newIndex = actionIndex == 0 ? 1 : 0;mScrollPointerId = event.getPointerId(newIndex);mLastTouchY = (int) (event.getY(newIndex) + 0.5f);}break;}case MotionEvent.ACTION_UP: {mVelocityTracker.addMovement(vtev);eventAddedToVelocityTracker = true;mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);float yVelocity = -VelocityTrackerCompat.getYVelocity(mVelocityTracker, mScrollPointerId);Log.i("zhufeng", "速度取值:" + yVelocity);if (Math.abs(yVelocity) < mMinFlingVelocity) {yVelocity = 0F;} else {yVelocity = Math.max(-mMaxFlingVelocity, Math.min(yVelocity, mMaxFlingVelocity));}if (yVelocity != 0) {mViewFlinger.fling((int) yVelocity);} else {setScrollState(SCROLL_STATE_IDLE);}resetTouch();break;}case MotionEvent.ACTION_CANCEL: {resetTouch();break;}}if (!eventAddedToVelocityTracker) {mVelocityTracker.addMovement(vtev);}vtev.recycle();return true;//return super.onTouchEvent(parent, child, ev);}private void resetTouch() {if (mVelocityTracker != null) {mVelocityTracker.clear();}}private void setScrollState(int state) {if (state == mScrollState) {return;}mScrollState = state;if (state != SCROLL_STATE_SETTLING) {mViewFlinger.stop();}}private class ViewFlinger implements Runnable {private int mLastFlingY = 0;private OverScroller mScroller;private boolean mEatRunOnAnimationRequest = false;private boolean mReSchedulePostAnimationCallback = false;private View mView;public ViewFlinger(Context context, View view) {this.mView = view;mScroller = new OverScroller(context, sQuinticInterpolator);}@Overridepublic void run() {disableRunOnAnimationRequests();final OverScroller scroller = mScroller;if (scroller.computeScrollOffset()) {final int y = scroller.getCurrY();int dy = y - mLastFlingY;mLastFlingY = y;constrainScrollBy(dy);postOnAnimation();}enableRunOnAnimationRequests();}public void fling(int velocityY) {mLastFlingY = 0;setScrollState(SCROLL_STATE_SETTLING);mScroller.fling(0, 0, 0, velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);postOnAnimation();}public void stop() {mView.removeCallbacks(this);mScroller.abortAnimation();}private void disableRunOnAnimationRequests() {mReSchedulePostAnimationCallback = false;mEatRunOnAnimationRequest = true;}private void enableRunOnAnimationRequests() {mEatRunOnAnimationRequest = false;if (mReSchedulePostAnimationCallback) {postOnAnimation();}}void postOnAnimation() {if (mEatRunOnAnimationRequest) {mReSchedulePostAnimationCallback = true;} else {mView.removeCallbacks(this);ViewCompat.postOnAnimation(mView, this);}}}private void constrainScrollBy(int dy) {/* Rect viewport = new Rect();getGlobalVisibleRect(viewport);int height = viewport.height();int width = viewport.width();*/if (parent == null) return;int height = getAllChildHeight(parent);int width = parent.getWidth();QDLogger.d("height=" + height + ",width=" + width);int scrollY = getFirstChild(parent).getTop();MultiRecycleContainer child = getCurrentChild(parent);//下边界if (mHeight - scrollY - dy < height) {dy = mHeight - scrollY - height;}//上边界if (scrollY + dy < 0) {dy = -scrollY;}// scroll(parent, child, dy);scrollParent(parent, child, null, dy);}//f(x) = (x-1)^5 + 1private static final Interpolator sQuinticInterpolator = new Interpolator() {@Overridepublic float getInterpolation(float t) {t -= 1.0f;return t * t * t * t * t + 1.0f;}};
}

Behavior部分负责管理多个容器的位置,并且负责协调滚动事件

使用部分

1.xml布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/white"><androidx.coordinatorlayout.widget.CoordinatorLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/transparent_light_77"><cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainerandroid:id="@+id/ssl_01"android:layout_width="match_parent"android:layout_height="wrap_content"android:colorBackground="@color/red"android:text="RecycleView A"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:id="@+id/ll_header_A"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/red"android:orientation="horizontal"android:paddingLeft="16dp"android:paddingTop="16dp"android:paddingBottom="36dp"><ImageViewandroid:layout_width="45dp"android:layout_height="45dp"android:padding="5dp"android:src="@drawable/umeng_socialize_sina" /><TextViewandroid:id="@+id/header_A"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:paddingLeft="15dp"android:text="斗气大陆"android:textColor="@color/white"android:textSize="32dp" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/list_A"android:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never"></androidx.recyclerview.widget.RecyclerView></LinearLayout></cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainer><cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainerandroid:id="@+id/ssl_02"android:layout_width="match_parent"android:layout_height="wrap_content"android:colorBackground="@color/green"android:text="RecycleView B"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:id="@+id/ll_header_B"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/green"android:orientation="horizontal"android:padding="6dp"><ImageViewandroid:layout_width="55dp"android:layout_height="55dp"android:padding="5dp"android:src="@drawable/shield" /><TextViewandroid:id="@+id/header_B"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_vertical"android:paddingLeft="10dp"android:text="再接再厉"android:textColor="@color/white"android:textSize="22dp" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/list_B"android:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never"></androidx.recyclerview.widget.RecyclerView></LinearLayout></cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainer><cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainerandroid:id="@+id/ssl_03"android:layout_width="match_parent"android:layout_height="wrap_content"android:colorBackground="@color/yellow"android:text="RecycleView C"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:id="@+id/ll_header_C"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/blue"android:orientation="horizontal"android:padding="6dp"><TextViewandroid:id="@+id/header_C"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_vertical"android:paddingLeft="15dp"android:text="人生如梦"android:textColor="@color/white"android:textSize="16dp"android:textStyle="bold" /><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:padding="5dp"android:src="@drawable/umeng_socialize_wxcircle" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/list_C"android:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never"></androidx.recyclerview.widget.RecyclerView></LinearLayout></cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainer><cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainerandroid:id="@+id/ssl_04"android:layout_width="match_parent"android:layout_height="wrap_content"android:colorBackground="@color/blue"android:text="RecycleView D"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:id="@+id/ll_header_D"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/yellow"android:orientation="horizontal"android:padding="6dp"><ImageViewandroid:layout_width="65dp"android:layout_height="65dp"android:padding="5dp"android:src="@drawable/umeng_socialize_fav" /><TextViewandroid:id="@+id/header_D"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_vertical"android:paddingLeft="15dp"android:text="艳阳高照"android:textColor="@color/black"android:textSize="28dp" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/list_D"android:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never"></androidx.recyclerview.widget.RecyclerView></LinearLayout></cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainer><cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainerandroid:id="@+id/ssl_05"android:layout_width="match_parent"android:layout_height="wrap_content"android:colorBackground="@color/chocolate"android:text="RecycleView E"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:id="@+id/ll_header_E"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/gray"android:orientation="horizontal"android:padding="6dp"><TextViewandroid:id="@+id/header_E"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:drawableLeft="@drawable/umeng_socialize_qzone"android:gravity="center_vertical"android:paddingLeft="15dp"android:text="过眼云烟"android:textColor="@color/white"android:textSize="22dp"android:textStyle="italic" /></LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/list_E"android:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never"></androidx.recyclerview.widget.RecyclerView></LinearLayout></cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.MultiRecycleContainer></androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
demo里用了5个recyclerView,看起来代码很多。其实就是CoordinatorLayout里包含多个MultiRecycleContainer
<CoordinatorLayout ><MultiRecycleContainer><LinearLayout><RecycleView/><其他布局/></LinearLayout></MultiRecycleContainer><MultiRecycleContainer><LinearLayout><RecycleView/><其他布局/></LinearLayout></MultiRecycleContainer>
</CoordinatorLayout >

2.java部分

package cn.demomaster.huan.quickdevelop.fragment.component;import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;
import java.util.List;import cn.demomaster.huan.quickdevelop.R;
import cn.demomaster.huan.quickdeveloplibrary.annotation.ActivityPager;
import cn.demomaster.huan.quickdeveloplibrary.annotation.ResType;
import cn.demomaster.huan.quickdeveloplibrary.base.fragment.QDBaseFragment;
import cn.demomaster.huan.quickdeveloplibrary.base.tool.actionbar.ActionBarInterface;
import cn.demomaster.huan.quickdeveloplibrary.view.loading.StateView;
import cn.demomaster.huan.quickdeveloplibrary.widget.stackslidingLayout.ComponentAdapter;/*** Squirrel桓* 2018/8/25*/@ActivityPager(name = "StackSliding", preViewClass = StateView.class, resType = ResType.Custome)
public class StackSlidingLayoutFragment extends QDBaseFragment {//ComponentsViewGroup mView;@Overridepublic int getBackgroundColor() {return Color.WHITE;}@Overridepublic ViewGroup getContentView(LayoutInflater inflater) {if (mView == null) {mView = (ViewGroup) inflater.inflate(R.layout.fragment_layout_stack_sliding, null);}return mView;}private RecyclerView recyclerView_A, recyclerView_B, recyclerView_C, recyclerView_D, recyclerView_E;private TextView header_A, header_B, header_C, header_D, header_E;private ComponentAdapter adapter_A, adapter_B, adapter_C, adapter_D, adapter_E;private List<String> items_A, items_B, items_C, items_D, items_E;@Overridepublic void initView(View rootView, ActionBarInterface actionBarLayout) {actionBarLayout.setActionBarType(ActionBarInterface.ACTIONBAR_TYPE.ACTION_TRANSPARENT);actionBarLayout.setHeaderBackgroundColor(Color.TRANSPARENT);//ArecyclerView_A = rootView.findViewById(R.id.list_A);header_A = rootView.findViewById(R.id.header_A);adapter_A = new ComponentAdapter(getContext(), Color.BLACK);items_A = new ArrayList();int c = 20;for (int i = 0; i < c; i++) {items_A.add("A" + i);}adapter_A.updateList(items_A);recyclerView_A.setAdapter(adapter_A);recyclerView_A.setLayoutManager(new LinearLayoutManager(getContext()));//BrecyclerView_B = rootView.findViewById(R.id.list_B);header_B = rootView.findViewById(R.id.header_B);adapter_B = new ComponentAdapter(getContext(), Color.BLACK);items_B = new ArrayList();c = 6;for (int i = 0; i < c; i++) {items_B.add("B" + i);}adapter_B.updateList(items_B);recyclerView_B.setAdapter(adapter_B);recyclerView_B.setLayoutManager(new LinearLayoutManager(getContext()));//CrecyclerView_C = rootView.findViewById(R.id.list_C);header_C = rootView.findViewById(R.id.header_C);adapter_C = new ComponentAdapter(getContext(), Color.BLACK);items_C = new ArrayList();c = 33;for (int i = 0; i < c; i++) {items_C.add("C" + i);}adapter_C.updateList(items_C);recyclerView_C.setAdapter(adapter_C);recyclerView_C.setLayoutManager(new LinearLayoutManager(getContext()));//DrecyclerView_D = rootView.findViewById(R.id.list_D);header_D = rootView.findViewById(R.id.header_D);adapter_D = new ComponentAdapter(getContext(), Color.BLACK);items_D = new ArrayList();c = 3;for (int i = 0; i < c; i++) {items_D.add("D" + i);}adapter_D.updateList(items_D);recyclerView_D.setAdapter(adapter_D);recyclerView_D.setLayoutManager(new LinearLayoutManager(getContext()));//ErecyclerView_E = rootView.findViewById(R.id.list_E);header_E = rootView.findViewById(R.id.header_E);adapter_E = new ComponentAdapter(getContext(), Color.BLACK);items_E = new ArrayList();c = 16;for (int i = 0; i < c; i++) {items_E.add("E" + i);}adapter_E.updateList(items_E);recyclerView_E.setAdapter(adapter_E);recyclerView_E.setLayoutManager(new LinearLayoutManager(getContext()));}@Overridepublic void onStop() {super.onStop();}
}

这部分没什么可说的,正常初始化使用recycleView和其他自定义布局。

遗留

每次最遗憾的是留了一个小尾巴,个人能力有限。1.使用网上的惯性滚动代码,效果不是很理想。2.惯性滑动跨越要把滑动事件传动给上一个recycler继续滑动,还没有处理好。

也是首次使用behavior做个记录,后面还想写写更多有意思的效果。

我的项目

allprojects {repositories {...maven { url 'https://jitpack.io' }}}
dependencies {implementation 'com.github.squirrelhuan:QuickDevelop:1.1.23'}

项目地址:https://github.com/squirrelhuan/QuickDevelop

这篇关于Behavior搭建多RecyclerView的复杂界面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/975628

相关文章

搭建Kafka+zookeeper集群调度

前言 硬件环境 172.18.0.5        kafkazk1        Kafka+zookeeper                Kafka Broker集群 172.18.0.6        kafkazk2        Kafka+zookeeper                Kafka Broker集群 172.18.0.7        kafkazk3

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

pico2 开发环境搭建-基于ubuntu

pico2 开发环境搭建-基于ubuntu 安装编译工具链下载sdk 和example编译example 安装编译工具链 sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib 注意cmake的版本,需要在3.17 以上 下载sdk 和ex

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

JavaFX环境的搭建和一个简单的例子

之前在网上搜了很多与javaFX相关的资料,都说要在Eclepse上要安装sdk插件什么的,反正就是乱七八糟的一大片,最后还是没搞成功,所以我在这里写下我搭建javaFX成功的环境给大家做一个参考吧。希望能帮助到你们! 1.首先要保证你的jdk版本能够支持JavaFX的开发,jdk-7u25版本以上的都能支持,最好安装jdk8吧,因为jdk8对支持JavaFX有新的特性了,比如:3D等;

springboot+maven搭建的项目,集成单元测试

springboot+maven搭建的项目,集成单元测试 1.在pom.xml文件中引入单元测试的依赖包 <!--单元测试依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></depen

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具,支持在一块屏幕上同时播放多个视频。其主要功能包括: 多视频播放:用户可以在一个窗口中同时播放任意数量的视频,数量仅受硬件性能限制。支持多种格式和流媒体:GridPlayer 支持所有由 VLC 支持的视频格式以及流媒体 URL(如 m3u8 链接)。自定义网格布局:用户可以配置播放器的网格布局,以适应不同的观看需求。硬

CentOS 7 SVN的搭建和使用

https://subversion.apache.org/packages.html#centos 阿里云的ECS貌似已经自带了SVN [root@xxx ~]# svn --versionsvn, version 1.7.14 (r1542130)compiled Aug 23 2017, 20:43:38Copyright (C) 2013 The Apache Software Fo

最近心情有点复杂:论心态

一月一次的彷徨又占据了整个身心;彷徨源至不自信;而不自信则是感觉自己的价值没有很好的实现亦或者说是自己不认可自己的目前的生活和状态吧。 我始终相信一句话:任何人的生活形态完全是由自己决定的;外在的总归不能直达一个人的内心深处。所以少年 为了自己想要的生活 多坚持努力吧、不为别人只为自己心中的那一丝执着。 由此我看到了一个故事: 一个心情烦躁的人去拜访禅师。他问禅师:我这辈子就这么注定了吗?您

2021-08-14 react笔记-1 安装、环境搭建、创建项目

1、环境 1、安装nodejs 2.安装react脚手架工具 //  cnpm install -g create-react-app 全局安装 2、创建项目 create-react-app [项目名称] 3、运行项目 npm strat  //cd到项目文件夹    进入这个页面  代表运行成功  4、打包 npm run build