https://github.com/ChenLittlePing/RecyclerCoverFlow

可以在github 搜索关键字 coverflow

package com.as.demo_ok6.coverflow;import android.animation.Animator;import android.animation.ValueAnimator;import android.graphics.ColorMatrix;import android.graphics.ColorMatrixColorFilter;import android.graphics.Paint;import android.graphics.Rect;import android.support.v7.widget.RecyclerView;import android.util.SparseArray;import android.util.SparseBooleanArray;import android.view.View;import android.view.ViewGroup;import android.view.animation.DecelerateInterpolator;/** * Cover Flow布局类 * 

通过重写LayoutManger布局方法{@link #onLayoutChildren(RecyclerView.Recycler, RecyclerView.State)} * 对Item进行布局,并对超出屏幕的Item进行回收 *

通过重写LayoutManger中的{@link #scrollHorizontallyBy(int, RecyclerView.Recycler, RecyclerView.State)} * 进行水平滚动处理 * * @author Chen Xiaoping (562818444@qq.com) * @version V1.0 * @Datetime 2017-04-18 */public class CoverFlowLayoutManger extends RecyclerView.LayoutManager { /** * 最大存储item信息存储数量, * 超过设置数量,则动态计算来获取 */ private final int MAX_RECT_COUNT = 100; /**滑动总偏移量*/ private int mOffsetAll = 0; /**Item宽*/ private int mDecoratedChildWidth = 0; /**Item高*/ private int mDecoratedChildHeight = 0; /**Item间隔与item宽的比例*/ private float mIntervalRatio = 0.5f; /**起始ItemX坐标*/ private int mStartX = 0; /**起始Item Y坐标*/ private int mStartY = 0; /**保存所有的Item的上下左右的偏移量信息*/ private SparseArray mAllItemFrames = new SparseArray<>(); /**记录Item是否出现过屏幕且还没有回收。true表示出现过屏幕上,并且还没被回收*/ private SparseBooleanArray mHasAttachedItems = new SparseBooleanArray(); /**RecyclerView的Item回收器*/ private RecyclerView.Recycler mRecycle; /**RecyclerView的状态器*/ private RecyclerView.State mState; /**滚动动画*/ private ValueAnimator mAnimation; /**正显示在中间的Item*/ private int mSelectPosition = 0; /**前一个正显示在中间的Item*/ private int mLastSelectPosition = 0; /**滑动的方向:左*/ private static int SCROLL_LEFT = 1; /**滑动的方向:右*/ private static int SCROLL_RIGHT = 2; /** * 选中监听 */ private OnSelected mSelectedListener; /**是否为平面滚动,Item之间没有叠加,也没有缩放*/ private boolean mIsFlatFlow = false; /**是否启动Item灰度值渐变*/ private boolean mItemGradualGrey = false; /**是否启动Item半透渐变*/ private boolean mItemGradualAlpha = false; public CoverFlowLayoutManger(boolean isFlat, boolean isGreyItem, boolean isAlphaItem, float cstInterval) { mIsFlatFlow = isFlat; mItemGradualGrey = isGreyItem; mItemGradualAlpha = isAlphaItem; if (cstInterval >= 0) { mIntervalRatio = cstInterval; } else { if (mIsFlatFlow) { mIntervalRatio = 1.1f; } } } @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { //如果没有item,直接返回 //跳过preLayout,preLayout主要用于支持动画 if (getItemCount() <= 0 || state.isPreLayout()) { mOffsetAll = 0; return; } mAllItemFrames.clear(); mHasAttachedItems.clear(); //得到子view的宽和高,这边的item的宽高都是一样的,所以只需要进行一次测量 View scrap = recycler.getViewForPosition(0); addView(scrap); measureChildWithMargins(scrap, 0, 0); //计算测量布局的宽高 mDecoratedChildWidth = getDecoratedMeasuredWidth(scrap); mDecoratedChildHeight = getDecoratedMeasuredHeight(scrap); mStartX = Math.round((getHorizontalSpace() - mDecoratedChildWidth) * 1.0f / 2); mStartY = Math.round((getVerticalSpace() - mDecoratedChildHeight) *1.0f / 2); float offset = mStartX; /**只存{@link MAX_RECT_COUNT}个item具体位置*/ for (int i = 0; i < getItemCount() && i < MAX_RECT_COUNT; i++) { Rect frame = mAllItemFrames.get(i); if (frame == null) { frame = new Rect(); } frame.set(Math.round(offset), mStartY, Math.round(offset + mDecoratedChildWidth), mStartY + mDecoratedChildHeight); mAllItemFrames.put(i, frame); mHasAttachedItems.put(i, false); offset = offset + getIntervalDistance(); //原始位置累加,否则越后面误差越大 } detachAndScrapAttachedViews(recycler); //在布局之前,将所有的子View先Detach掉,放入到Scrap缓存中 if ((mRecycle == null || mState == null) && //在为初始化前调用smoothScrollToPosition 或者 scrollToPosition,只会记录位置 mSelectPosition != 0) { //所以初始化时需要滚动到对应位置 mOffsetAll = calculateOffsetForPosition(mSelectPosition); onSelectedCallBack(); } layoutItems(recycler, state, SCROLL_RIGHT); mRecycle = recycler; mState = state; } @Override public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { if (mAnimation != null && mAnimation.isRunning()) mAnimation.cancel(); int travel = dx; if (dx + mOffsetAll < 0) { travel = -mOffsetAll; } else if (dx + mOffsetAll > getMaxOffset()){ travel = (int) (getMaxOffset() - mOffsetAll); } mOffsetAll += travel; //累计偏移量 layoutItems(recycler, state, dx > 0 ? SCROLL_RIGHT : SCROLL_LEFT); return travel; } /** * 布局Item *

注意:1,先清除已经超出屏幕的item *

2,再绘制可以显示在屏幕里面的item */ private void layoutItems(RecyclerView.Recycler recycler, RecyclerView.State state, int scrollDirection) { if (state.isPreLayout()) return; Rect displayFrame = new Rect(mOffsetAll, 0, mOffsetAll + getHorizontalSpace(), getVerticalSpace()); int position = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); position = getPosition(child); Rect rect = getFrame(position); if (!Rect.intersects(displayFrame, rect)) {//Item没有在显示区域,就说明需要回收 removeAndRecycleView(child, recycler); //回收滑出屏幕的View mHasAttachedItems.delete(position); } else { //Item还在显示区域内,更新滑动后Item的位置 layoutItem(child, rect); //更新Item位置 mHasAttachedItems.put(position, true); } } if (position == 0) position = mSelectPosition; int min = position - 50 >= 0? position - 50 : 0; int max = position + 50 < getItemCount() ? position + 50 : getItemCount(); for (int i = min; i < max; i++) { Rect rect = getFrame(i); if (Rect.intersects(displayFrame, rect) && !mHasAttachedItems.get(i)) { //重新加载可见范围内的Item View scrap = recycler.getViewForPosition(i); measureChildWithMargins(scrap, 0, 0); if (scrollDirection == SCROLL_LEFT || mIsFlatFlow) { //向左滚动,新增的Item需要添加在最前面 addView(scrap, 0); } else { //向右滚动,新增的item要添加在最后面 addView(scrap); } layoutItem(scrap, rect); //将这个Item布局出来 mHasAttachedItems.put(i, true); } } } /** * 布局Item位置 * @param child 要布局的Item * @param frame 位置信息 */ private void layoutItem(View child, Rect frame) { layoutDecorated(child, frame.left - mOffsetAll, frame.top, frame.right - mOffsetAll, frame.bottom); if (!mIsFlatFlow) { //不是平面普通滚动的情况下才进行缩放 child.setScaleX(computeScale(frame.left - mOffsetAll)); //缩放 child.setScaleY(computeScale(frame.left - mOffsetAll)); //缩放 } if (mItemGradualAlpha) { child.setAlpha(computeAlpha(frame.left - mOffsetAll)); } if (mItemGradualGrey) { greyItem(child, frame); } } /** * 动态获取Item的位置信息 * @param index item位置 * @return item的Rect信息 */ private Rect getFrame(int index) { Rect frame = mAllItemFrames.get(index); if (frame == null) { frame = new Rect(); float offset = mStartX + getIntervalDistance() * index; //原始位置累加(即累计间隔距离) frame.set(Math.round(offset), mStartY, Math.round(offset + mDecoratedChildWidth), mStartY + mDecoratedChildHeight); } return frame; } /** * 变化Item的灰度值 * @param child 需要设置灰度值的Item * @param frame 位置信息 */ private void greyItem(View child, Rect frame) { float value = computeGreyScale(frame.left - mOffsetAll); ColorMatrix cm = new ColorMatrix(new float[]{ value, 0, 0, 0, 120*(1-value), 0, value, 0, 0, 120*(1-value), 0, 0, value, 0, 120*(1-value), 0, 0, 0, 1, 250*(1-value), });// cm.setSaturation(0.9f); // Create a paint object with color matrix Paint greyPaint = new Paint(); greyPaint.setColorFilter(new ColorMatrixColorFilter(cm)); // Create a hardware layer with the grey paint child.setLayerType(View.LAYER_TYPE_HARDWARE, greyPaint); if (value >= 1) { // Remove the hardware layer child.setLayerType(View.LAYER_TYPE_NONE, null); } } @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); switch (state){ case RecyclerView.SCROLL_STATE_IDLE: //滚动停止时 fixOffsetWhenFinishScroll(); break; case RecyclerView.SCROLL_STATE_DRAGGING: //拖拽滚动时 break; case RecyclerView.SCROLL_STATE_SETTLING: //动画滚动时 break; } } @Override public void scrollToPosition(int position) { if (position < 0 || position > getItemCount() - 1) return; mOffsetAll = calculateOffsetForPosition(position); if (mRecycle == null || mState == null) {//如果RecyclerView还没初始化完,先记录下要滚动的位置 mSelectPosition = position; } else { layoutItems(mRecycle, mState, position > mSelectPosition ? SCROLL_RIGHT : SCROLL_LEFT); onSelectedCallBack(); } } @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { int finalOffset = calculateOffsetForPosition(position); if (mRecycle == null || mState == null) {//如果RecyclerView还没初始化完,先记录下要滚动的位置 mSelectPosition = position; } else { startScroll(mOffsetAll, finalOffset); } } @Override public boolean canScrollHorizontally() { return true; } @Override public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) { removeAllViews(); mRecycle = null; mState = null; mOffsetAll = 0; mSelectPosition = 0; mLastSelectPosition = 0; mHasAttachedItems.clear(); mAllItemFrames.clear(); } /** * 获取整个布局的水平空间大小 */ private int getHorizontalSpace() { return getWidth() - getPaddingRight() - getPaddingLeft(); } /** * 获取整个布局的垂直空间大小 */ private int getVerticalSpace() { return getHeight() - getPaddingBottom() - getPaddingTop(); } /** * 获取最大偏移量 */ private float getMaxOffset() { return (getItemCount() - 1) * getIntervalDistance(); } /** * 计算Item缩放系数 * @param x Item的偏移量 * @return 缩放系数 */ private float computeScale(int x) { float scale = 1 - Math.abs(x - mStartX) * 1.0f / Math.abs(mStartX + mDecoratedChildWidth / mIntervalRatio); if (scale < 0) scale = 0; if (scale > 1) scale = 1; return scale; } /** * 计算Item的灰度值 * @param x Item的偏移量 * @return 灰度系数 */ private float computeGreyScale(int x) { float itemMidPos = x + mDecoratedChildWidth / 2; //item中点x坐标 float itemDx2Mid = Math.abs(itemMidPos - getHorizontalSpace() / 2); //item中点距离控件中点距离 float value = 1 - itemDx2Mid * 1.0f / (getHorizontalSpace() /2); if (value < 0.1) value = 0.1f; if (value > 1) value = 1; value = (float) Math.pow(value,.8); return value; } /** * 计算Item半透值 * @param x Item的偏移量 * @return 缩放系数 */ private float computeAlpha(int x) { float alpha = 1 - Math.abs(x - mStartX) * 1.0f / Math.abs(mStartX + mDecoratedChildWidth / mIntervalRatio); if (alpha < 0.3f) alpha = 0.3f; if (alpha > 1) alpha = 1.0f; return alpha; } /** * 计算Item所在的位置偏移 * @param position 要计算Item位置 */ private int calculateOffsetForPosition(int position) { return Math.round(getIntervalDistance() * position); } /** * 修正停止滚动后,Item滚动到中间位置 */ private void fixOffsetWhenFinishScroll() { int scrollN = (int) (mOffsetAll * 1.0f / getIntervalDistance()); float moreDx = (mOffsetAll % getIntervalDistance()); if (moreDx > (getIntervalDistance() * 0.5)) { scrollN ++; } int finalOffset = (int) (scrollN * getIntervalDistance()); startScroll(mOffsetAll, finalOffset); mSelectPosition = Math.round (finalOffset * 1.0f / getIntervalDistance()); } /** * 滚动到指定X轴位置 * @param from X轴方向起始点的偏移量 * @param to X轴方向终点的偏移量 */ private void startScroll(int from, int to) { if (mAnimation != null && mAnimation.isRunning()) { mAnimation.cancel(); } final int direction = from < to ? SCROLL_RIGHT : SCROLL_LEFT; mAnimation = ValueAnimator.ofFloat(from, to); mAnimation.setDuration(500); mAnimation.setInterpolator(new DecelerateInterpolator()); mAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mOffsetAll = Math.round((float) animation.getAnimatedValue()); layoutItems(mRecycle, mState, direction); } }); mAnimation.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { onSelectedCallBack(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); mAnimation.start(); } /** * 获取Item间隔 */ private float getIntervalDistance() { return mDecoratedChildWidth * mIntervalRatio; } /** * 计算当前选中位置,并回调 */ private void onSelectedCallBack() { mSelectPosition = Math.round (mOffsetAll / getIntervalDistance()); if (mSelectedListener != null && mSelectPosition != mLastSelectPosition) { mSelectedListener.onItemSelected(mSelectPosition); } mLastSelectPosition = mSelectPosition; } /** * 获取第一个可见的Item位置 *

Note:该Item为绘制在可见区域的第一个Item,有可能被第二个Item遮挡 */ public int getFirstVisiblePosition() { Rect displayFrame = new Rect(mOffsetAll, 0, mOffsetAll + getHorizontalSpace(), getVerticalSpace()); int cur = getCenterPosition(); for (int i = cur - 1; i >= 0; i--) { Rect rect = getFrame(i); if (!Rect.intersects(displayFrame, rect)) { return i + 1; } } return 0; } /** * 获取最后一个可见的Item位置 *

Note:该Item为绘制在可见区域的最后一个Item,有可能被倒数第二个Item遮挡 */ public int getLastVisiblePosition() { Rect displayFrame = new Rect(mOffsetAll, 0, mOffsetAll + getHorizontalSpace(), getVerticalSpace()); int cur = getCenterPosition(); for (int i = cur + 1; i < getItemCount(); i++) { Rect rect = getFrame(i); if (!Rect.intersects(displayFrame, rect)) { return i - 1; } } return cur; } /** * 获取可见范围内最大的显示Item个数 */ public int getMaxVisibleCount() { int oneSide = (int) ((getHorizontalSpace() - mStartX) / (getIntervalDistance())); return oneSide * 2 + 1; } /** * 获取中间位置 *

Note:该方法主要用于{@link RecyclerCoverFlow#getChildDrawingOrder(int, int)}判断中间位置 *

如果需要获取被选中的Item位置,调用{@link #getSelectedPos()} */ public int getCenterPosition() { int pos = (int) (mOffsetAll / getIntervalDistance()); int more = (int) (mOffsetAll % getIntervalDistance()); if (more > getIntervalDistance() * 0.5f) pos++; return pos; } /** * 设置选中监听 * @param l 监听接口 */ public void setOnSelectedListener(OnSelected l) { mSelectedListener = l; } /** * 获取被选中Item位置 */ public int getSelectedPos() { return mSelectPosition; } /** * 选中监听接口 */ public interface OnSelected { /** * 监听选中回调 * @param position 显示在中间的Item的位置 */ void onItemSelected(int position); } public static class Builder { boolean isFlat = false; boolean isGreyItem = false; boolean isAlphaItem = false; float cstIntervalRatio = -1f; public Builder setFlat(boolean flat) { isFlat = flat; return this; } public Builder setGreyItem(boolean greyItem) { isGreyItem = greyItem; return this; } public Builder setAlphaItem(boolean alphaItem) { isAlphaItem = alphaItem; return this; } public Builder setIntervalRatio(float ratio) { cstIntervalRatio = ratio; return this; } public CoverFlowLayoutManger build() { return new CoverFlowLayoutManger(isFlat, isGreyItem, isAlphaItem, cstIntervalRatio); } }}

 

package com.as.demo_ok6.coverflow;import android.content.Context;import android.support.annotation.Nullable;import android.support.v7.widget.RecyclerView;import android.util.AttributeSet;import android.view.MotionEvent;/** * 继承RecyclerView重写{@link #getChildDrawingOrder(int, int)}对Item的绘制顺序进行控制 * * @author Chen Xiaoping (562818444@qq.com) * @version V1.0 * @Datetime 2017-04-18 */public class RecyclerCoverFlow extends RecyclerView {    /**     * 按下的X轴坐标     */    private float mDownX;    /**     * 布局器构建者     */    private CoverFlowLayoutManger.Builder mManagerBuilder;    public RecyclerCoverFlow(Context context) {        super(context);        init();    }    public RecyclerCoverFlow(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init();    }    public RecyclerCoverFlow(Context context, @Nullable AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();    }    private void init() {        createManageBuilder();        setLayoutManager(mManagerBuilder.build());        setChildrenDrawingOrderEnabled(true); //开启重新排序        setOverScrollMode(OVER_SCROLL_NEVER);    }    /**     * 创建布局构建器     */    private void createManageBuilder() {        if (mManagerBuilder == null) {            mManagerBuilder = new CoverFlowLayoutManger.Builder();        }    }    /**     * 设置是否为普通平面滚动     * @param isFlat true:平面滚动;false:叠加缩放滚动     */    public void setFlatFlow(boolean isFlat) {        createManageBuilder();        mManagerBuilder.setFlat(isFlat);        setLayoutManager(mManagerBuilder.build());    }    /**     * 设置Item灰度渐变     * @param greyItem true:Item灰度渐变;false:Item灰度不变     */    public void setGreyItem(boolean greyItem) {        createManageBuilder();        mManagerBuilder.setGreyItem(greyItem);        setLayoutManager(mManagerBuilder.build());    }    /**     * 设置Item灰度渐变     * @param alphaItem true:Item半透渐变;false:Item透明度不变     */    public void setAlphaItem(boolean alphaItem) {        createManageBuilder();        mManagerBuilder.setAlphaItem(alphaItem);        setLayoutManager(mManagerBuilder.build());    }    /**     * 设置Item的间隔比例     * @param intervalRatio Item间隔比例。     *                      即:item的宽 x intervalRatio     */    public void setIntervalRatio(float intervalRatio) {        createManageBuilder();        mManagerBuilder.setIntervalRatio(intervalRatio);        setLayoutManager(mManagerBuilder.build());    }    @Override    public void setLayoutManager(LayoutManager layout) {        if (!(layout instanceof CoverFlowLayoutManger)) {            throw new IllegalArgumentException("The layout manager must be CoverFlowLayoutManger");        }        super.setLayoutManager(layout);    }    @Override    protected int getChildDrawingOrder(int childCount, int i) {        int center = getCoverFlowLayout().getCenterPosition()                - getCoverFlowLayout().getFirstVisiblePosition(); //计算正在显示的所有Item的中间位置        if (center < 0) center = 0;        else if (center > childCount) center = childCount;        int order;        if (i == center) {            order = childCount - 1;        } else if (i > center) {            order = center + childCount - 1 - i;        } else {            order = i;        }        return order;    }    /**     * 获取LayoutManger,并强制转换为CoverFlowLayoutManger     */    public CoverFlowLayoutManger getCoverFlowLayout() {        return ((CoverFlowLayoutManger)getLayoutManager());    }    /**     * 获取被选中的Item位置     */    public int getSelectedPos() {        return getCoverFlowLayout().getSelectedPos();    }    /**     * 设置选中监听     * @param l 监听接口     */    public void setOnItemSelectedListener(CoverFlowLayoutManger.OnSelected l) {        getCoverFlowLayout().setOnSelectedListener(l);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                mDownX = ev.getX();                getParent().requestDisallowInterceptTouchEvent(true); //设置父类不拦截滑动事件                break;            case MotionEvent.ACTION_MOVE:                if ((ev.getX() > mDownX && getCoverFlowLayout().getCenterPosition() == 0) ||                        (ev.getX() < mDownX && getCoverFlowLayout().getCenterPosition() ==                                getCoverFlowLayout().getItemCount() -1)) {                    //如果是滑动到了最前和最后,开放父类滑动事件拦截                    getParent().requestDisallowInterceptTouchEvent(false);                } else {                    //滑动到中间,设置父类不拦截滑动事件                    getParent().requestDisallowInterceptTouchEvent(true);                }                break;        }        return super.dispatchTouchEvent(ev);    }}

https://github.com/zhangqifan1/Demo_ok6


2.https://github.com/zhangqifan1/FlyPiyInSky  s烧烤摊里面有很多

 

3.OverFlying 这个 ViewPager 其实有个这种的 RecyclerView 的 也不错 

public class OverFlyingLayoutManager extends RecyclerView.LayoutManager {    private static final String TAG = "OverFlying";    private @FloatRange(from = 0.01, to = 1.0)    float edgePercent = 0.8f;//触发边缘动画距离百分比    private @FloatRange(from = 1)    float slowTimes = 3;//到达此距离后放慢倍数    private int orientation = OrientationHelper.VERTICAL;    private boolean offsetUseful = false;    private int overFlyingDist;    private int totalHeight = 0;    private int totalWidth = 0;    private int verticalScrollOffset;    private int horizontalScrollOffset;    //头部是否也要层叠,默认需要    private boolean topOverFlying;    private int viewWidth, viewHeight;    public OverFlyingLayoutManager() {        this(OrientationHelper.VERTICAL);    }    public OverFlyingLayoutManager(int orientation) {        this(orientation, true);    }    public OverFlyingLayoutManager(int orientation, boolean topOverFlying) {        this.orientation = orientation;        this.topOverFlying = topOverFlying;    }    @Override    public RecyclerView.LayoutParams generateDefaultLayoutParams() {        return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);    }    @Override    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {        super.onLayoutChildren(recycler, state);        // 先把所有的View先从RecyclerView中detach掉,然后标记为"Scrap"状态,表示这些View处于可被重用状态(非显示中)。        // 实际就是把View放到了Recycler中的一个集合中。        if (getItemCount() == 0) {//没有Item            detachAndScrapAttachedViews(recycler);            return;        }        if (getChildCount() == 0 && state.isPreLayout()) {            return;        }        reset();        detachAndScrapAttachedViews(recycler);        calculateChildrenSite(recycler, state);    }    private void reset() {        totalHeight = 0;        totalWidth = 0;        if (!offsetUseful) {            verticalScrollOffset = 0;            horizontalScrollOffset = 0;        }        offsetUseful = false;    }    private void calculateChildrenSite(RecyclerView.Recycler recycler, RecyclerView.State state) {        if (orientation == OrientationHelper.VERTICAL) {            calculateChildrenSiteVertical(recycler, state);            addAndLayoutViewVertical(recycler, state, verticalScrollOffset);        } else {            calculateChildrenSiteHorizontal(recycler, state);            addAndLayoutViewHorizontal(recycler, state, horizontalScrollOffset);        }    }    private void calculateChildrenSiteVertical(RecyclerView.Recycler recycler, RecyclerView.State state) {        View view = recycler.getViewForPosition(0);//暂时这么解决,不能layout出所有的子View        measureChildWithMargins(view, 0, 0);        calculateItemDecorationsForChild(view, new Rect());        viewHeight = getDecoratedMeasuredHeight(view);        overFlyingDist = (int) (slowTimes * viewHeight);        totalHeight = getItemCount() * viewHeight;        Log.d(TAG, "childCountI = " + getChildCount() + "  itemCount= " + recycler.getScrapList().size());    }    private void calculateChildrenSiteHorizontal(RecyclerView.Recycler recycler, RecyclerView.State state) {        View view = recycler.getViewForPosition(0);//暂时这么解决,不能layout出所有的子View        measureChildWithMargins(view, 0, 0);        calculateItemDecorationsForChild(view, new Rect());        viewWidth = getDecoratedMeasuredWidth(view);        overFlyingDist = (int) (slowTimes * viewWidth);        totalWidth = getItemCount() * viewWidth;        Log.d(TAG, "childCountI = " + getChildCount() + "  itemCount= " + recycler.getScrapList().size());    }    @Override    public boolean canScrollHorizontally() {        // 返回true表示可以横向滑动        return orientation == OrientationHelper.HORIZONTAL;    }    @Override    public boolean canScrollVertically() {        // 返回true表示可以纵向滑动        return orientation == OrientationHelper.VERTICAL;    }    @Override    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {        //列表向下滚动dy为正,列表向上滚动dy为负,这点与Android坐标系保持一致。        int tempDy = dy;        if (verticalScrollOffset <= totalHeight - getVerticalSpace()) {            verticalScrollOffset += dy;            //将竖直方向的偏移量+travel        }        if (verticalScrollOffset > totalHeight - getVerticalSpace()) {            verticalScrollOffset = totalHeight - getVerticalSpace();            tempDy = 0;        } else if (verticalScrollOffset < 0) {            verticalScrollOffset = 0;            tempDy = 0;        }        detachAndScrapAttachedViews(recycler);        addAndLayoutViewVertical(recycler, state, verticalScrollOffset); //从新布局位置、显示View        return tempDy;    }    @Override    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {        int tempDx = dx;        if (horizontalScrollOffset <= totalWidth - getHorizontalSpace()) {            horizontalScrollOffset += dx;            //将竖直方向的偏移量+travel        }        if (horizontalScrollOffset > totalWidth - getHorizontalSpace()) {            horizontalScrollOffset = totalWidth - getHorizontalSpace();            tempDx = 0;        } else if (horizontalScrollOffset < 0) {            horizontalScrollOffset = 0;            tempDx = 0;        }        detachAndScrapAttachedViews(recycler);        addAndLayoutViewHorizontal(recycler, state, horizontalScrollOffset); //从新布局位置、显示View        return tempDx;    }    private void addAndLayoutViewVertical(RecyclerView.Recycler recycler, RecyclerView.State state, int offset) {        int itemCount = getItemCount();        if (itemCount <= 0 || state.isPreLayout()) {            return;        }        int displayHeight = getVerticalSpace();        for (int i = itemCount - 1; i >= 0; i--) {            // 遍历Recycler中保存的View取出来            int bottomOffset = (i + 1) * viewHeight - offset;            int topOffset = i * viewHeight - offset;            boolean needAdd = true;            if (bottomOffset - displayHeight >= overFlyingDist) {                needAdd = false;            }            if (topOffset < -overFlyingDist && i != 0 && topOverFlying                    || topOffset < -overFlyingDist && !topOverFlying) {                needAdd = false;            }            if (needAdd) {                View view = recycler.getViewForPosition(i);                addView(view); // 因为刚刚进行了detach操作,所以现在可以重新添加                measureChildWithMargins(view, 0, 0); // 通知测量view的margin值                int width = getDecoratedMeasuredWidth(view); // 计算view实际大小,包括了ItemDecorator中设置的偏移量。                int height = getDecoratedMeasuredHeight(view);                //调用这个方法能够调整ItemView的大小,以除去ItemDecorator。                calculateItemDecorationsForChild(view, new Rect());                int realBottomOffset = bottomOffset;                if (topOverFlying) {                    if (i != 0) {//除第一个外的顶部黏性动画                        if (topOffset <= height * edgePercent) {//到达顶部边界了                            int edgeDist = (int) (height * edgePercent);//边界触发距离                            int top = (int) (edgeDist - (edgeDist - topOffset) / slowTimes);//到达边界后速度放慢到原来5分之一                            top = Math.max(top, 0);                            realBottomOffset = top + height;                        }                    } else {                        realBottomOffset = height;                    }                }                if (i != itemCount - 1) {//除最后一个外的底部慢速动画                    if (displayHeight - bottomOffset <= height * edgePercent) {                        int edgeDist = (int) (displayHeight - height * edgePercent);                        int bottom = (int) (edgeDist + (bottomOffset - edgeDist) / slowTimes);                        bottom = Math.min(bottom, displayHeight);                        realBottomOffset = bottom;                    }                } else {                    realBottomOffset = totalHeight > displayHeight ? displayHeight : totalHeight;                }                layoutDecoratedWithMargins(view, 0, realBottomOffset - height, width, realBottomOffset);            }        }        Log.d(TAG, "childCount = " + getChildCount() + "  itemCount= " + itemCount);    }    private void addAndLayoutViewHorizontal(RecyclerView.Recycler recycler, RecyclerView.State state, int offset) {        int itemCount = getItemCount();        if (itemCount <= 0 || state.isPreLayout()) {            return;        }        int displayWidth = getHorizontalSpace();        for (int i = itemCount - 1; i >= 0; i--) {            int rightOffset = (i + 1) * viewWidth - offset;            int leftOffset = i * viewWidth - offset;            boolean needAdd = true;            if (rightOffset - displayWidth >= overFlyingDist) {                needAdd = false;            }            if (leftOffset < -overFlyingDist && i != 0                    || leftOffset < -overFlyingDist && !topOverFlying) {                needAdd = false;            }            if (needAdd) {                // 遍历Recycler中保存的View取出来                View view = recycler.getViewForPosition(i);                addView(view); // 因为刚刚进行了detach操作,所以现在可以重新添加                measureChildWithMargins(view, 0, 0); // 通知测量view的margin值                int width = getDecoratedMeasuredWidth(view); // 计算view实际大小,包括了ItemDecorator中设置的偏移量。                int height = getDecoratedMeasuredHeight(view);                //调用这个方法能够调整ItemView的大小,以除去ItemDecorator。                calculateItemDecorationsForChild(view, new Rect());                int realRightOffset = rightOffset;                if (topOverFlying) {//除第一个外的左边缘慢速动画                    if (i != 0) {                        if (leftOffset <= width * edgePercent) {//到达边界了                            int edgeDist = (int) (width * edgePercent);//边界触发距离                            int left = (int) (edgeDist - (edgeDist - leftOffset) / slowTimes);///到达边界后速度放慢到原来5分之一                            left = Math.max(0, left);                            if (left < 0) {                                left = 0;                            }                            realRightOffset = left + width;                        }                    } else {                        realRightOffset = width;                    }                }                if (i != itemCount - 1) {//除最后一个外的右边缘慢速动画                    if (displayWidth - rightOffset <= width * edgePercent) {                        int edgeDist = (int) (displayWidth - width * edgePercent);                        int right = (int) (edgeDist + (rightOffset - edgeDist) / slowTimes);                        if (right >= displayWidth) {                            right = displayWidth;                        }                        realRightOffset = right;                    }                } else {                    realRightOffset = totalWidth > displayWidth ? displayWidth : totalWidth;                }                layoutDecoratedWithMargins(view, realRightOffset - width, 0, realRightOffset, height);            }        }        Log.d(TAG, "childCount = " + getChildCount() + "  itemCount= " +itemCount);    }    private int getVerticalSpace() {        // 计算RecyclerView的可用高度,除去上下Padding值        return getHeight() - getPaddingBottom() - getPaddingTop();    }    private int getHorizontalSpace() {        return getWidth() - getPaddingLeft() - getPaddingRight();    }    public void setEdgePercent(@FloatRange(from = 0.01, to = 1.0) float edgePercent) {        this.edgePercent = edgePercent;    }    /**     * {@inheritDoc}     */    @Override    public View findViewByPosition(int position) {        final int childCount = getChildCount();        if (childCount == 0) {            return null;        }        final int firstChild = getPosition(getChildAt(0));        final int viewPosition = position - firstChild;        if (viewPosition >= 0 && viewPosition < childCount) {            final View child = getChildAt(viewPosition);            if (getPosition(child) == position) {                return child; // in pre-layout, this may not match            }        }        return super.findViewByPosition(position);    }    @Override    public void scrollToPosition(int position) {        offsetUseful = true;        if (orientation == OrientationHelper.VERTICAL && viewHeight != 0) {            verticalScrollOffset = position * viewHeight;        } else if (orientation == OrientationHelper.HORIZONTAL && viewWidth != 0) {            horizontalScrollOffset = position * viewWidth;        }        requestLayout();    }    public void setSlowTimes(@IntRange(from = 1) int slowTimes) {        this.slowTimes = slowTimes;    }}
<?xml version="1.0" encoding="utf-8"?>                
        List list = new ArrayList() {{            for (int i = 0; i < 100; i++) {                add("  "+i+"  ");            }        }};        /*******0*******/        final RecyclerView recycelrview = findViewById(R.id.recycelrview);        OverFlyingLayoutManager overFlyingLayoutManager = new OverFlyingLayoutManager(OrientationHelper.HORIZONTAL);        recycelrview.setLayoutManager(overFlyingLayoutManager);        MyAdapter myAdapter = new MyAdapter(R.layout.item_text, list);        recycelrview.setAdapter(myAdapter);        /*******1*******/        final RecyclerView recycelrview1 = findViewById(R.id.recycelrview1);        OverFlyingLayoutManager overFlyingLayoutManager1 = new OverFlyingLayoutManager(OrientationHelper.HORIZONTAL,false);        recycelrview1.setLayoutManager(overFlyingLayoutManager1);        MyAdapter myAdapter1 = new MyAdapter(R.layout.item_text, list);        recycelrview1.setAdapter(myAdapter1);        /*******2*******/        final RecyclerView recycelrview2 = findViewById(R.id.recycelrview2);        OverFlyingLayoutManager overFlyingLayoutManager2 = new OverFlyingLayoutManager(OrientationHelper.VERTICAL);        recycelrview2.setLayoutManager(overFlyingLayoutManager2);        MyAdapter myAdapter2 = new MyAdapter(R.layout.item_text, list);        recycelrview2.setAdapter(myAdapter2);        /*******3*******/        final RecyclerView recycelrview3 = findViewById(R.id.recycelrview3);        OverFlyingLayoutManager overFlyingLayoutManager3 = new OverFlyingLayoutManager(OrientationHelper.VERTICAL,false);        recycelrview3.setLayoutManager(overFlyingLayoutManager3);        MyAdapter myAdapter3 = new MyAdapter(R.layout.item_text, list);        recycelrview3.setAdapter(myAdapter3);
<?xml version="1.0" encoding="utf-8"?>    

首先RecyclerView 不能wrap_content 第二 条目的 宽高影响着效果


4.https://github.com/DingMouRen/LayoutManagerGroup  这个也很多

 

 

 

更多相关文章

  1. 改变滚动条的颜色ScrollView
  2. Android(安卓)ListView滑动回弹——overScrollBy
  3. Android布局文件.xml中的自定义属性(结合封装的自定义View)
  4. android获取recycleview滚动的距离
  5. absolutelayout 实现图片重叠
  6. Android在布局文件指定位置动态增加删除布局
  7. smartrefreshlayout 只开启纯滚动模式
  8. ViewFlipper实现View轮播点击等效果
  9. Android(安卓)Gallery获取滑动停止的位置

随机推荐

  1. Android(安卓)studio gradle 配置阿里镜
  2. Android(安卓)关于微信分享图片过大失败
  3. android应用安全——组件通信安全(Intent)
  4. 时间和日期选择器DatePicker和TimePicker
  5. Android桌面小组件:最简例子
  6. 相机的研究
  7. Android(安卓)MPChart—柱状图
  8. Flutter ------- WebView加载网页
  9. Android使用的SQLite数据库
  10. 处理运行时更改