美文网首页IT/互联网
9.Android RecyclerView 画廊 自定

9.Android RecyclerView 画廊 自定

作者: 鹏城十八少 | 来源:发表于2021-07-03 20:16 被阅读0次

    今天开始讲RecycleView的系列教程。分割线,分组,局部刷新,动态添加,缓存原理,抖音效果,瀑布流。嵌套,动画等等

    从月薪3000到年薪60万。从专科生到深圳一线大厂。关注我就能达到大师级水平,这话我终于敢说了, 年薪60万不是梦!

    请问:简书怎么可以把代码格式调整?我贴出来换格式了。你们直接去Github下载工程!

    功能:

    支持无限循环

    支持画廊效果

    支持中间放大并定格

    支持方向切换

    支持回弹效果

    效果分析

    1.优先实现圆弧效果

    2.然后实现放大效果

    3.实现定格效果

    原理:使用recyclerview的话你只需通过setAdapter方法改变数据,setLayoutManager方法改变样式即可,

    重写LayoutManager。我们自定义ViewPagerLayoutManager extends LinearLayoutManager 然后二次封装:

    /**

    * 可缩放的弧形菜单

    */

    public class CircleScaleLayoutManagerextends ViewPagerLayoutManager {

    圆弧效果

    给每个item设置旋转角度

    itemView.setRotation(targetOffset);

    @Override

    protected void setItemViewProperty(View itemView, float targetOffset) {

    switch (gravity) {

    case RIGHT:

    case TOP:

    if (flipRotate) {

    itemView.setRotation(targetOffset);

                }else {

    itemView.setRotation(360 - targetOffset);

                }

    break;

            case LEFT:

    case BOTTOM:

    default:

    if (flipRotate) {

    itemView.setRotation(360 - targetOffset);

                }else {

    itemView.setRotation(targetOffset);

                }

    break;

        }

    }

    然后实现放大效果 itemView.setScaleX(scale);

    @Override

    protected void setItemViewProperty(View itemView, float targetOffset) {

    float scale =1f;

        switch (gravity) {

    case RIGHT:

    case TOP:

    if (flipRotate) {

    itemView.setRotation(targetOffset);

                    if (targetOffset -angleInterval) {

    float diff = Math.abs(Math.abs(itemView.getRotation() -angleInterval) -angleInterval);

                        scale = (centerScale -1f) / -angleInterval * diff +centerScale;

                    }

    }else {

    itemView.setRotation(360 - targetOffset);

                    if (targetOffset -angleInterval) {

    float diff = Math.abs(Math.abs(360 - itemView.getRotation() -angleInterval) -angleInterval);

                        scale = (centerScale -1f) / -angleInterval * diff +centerScale;

                    }

    }

    break;

            case LEFT:

    case BOTTOM:

    default:

    if (flipRotate) {

    itemView.setRotation(360 - targetOffset);

                    if (targetOffset -angleInterval) {

    float diff = Math.abs(Math.abs(360 - itemView.getRotation() -angleInterval) -angleInterval);

                        scale = (centerScale -1f) / -angleInterval * diff +centerScale;

                    }

    }else {

    itemView.setRotation(targetOffset);

                    if (targetOffset -angleInterval) {

    float diff = Math.abs(Math.abs(itemView.getRotation() -angleInterval) -angleInterval);

                        scale = (centerScale -1f) / -angleInterval * diff +centerScale;

                    }

    }

    break;

        }

    itemView.setScaleX(scale);

        itemView.setScaleY(scale);

    }

    3.实现定格效果:通过监听RecyclerView的滚动方法

    private final RecyclerView.OnScrollListenermScrollListener =

    new RecyclerView.OnScrollListener() {

    boolean mScrolled =false;

                @Override

                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

    super.onScrollStateChanged(recyclerView, newState);

                    final ViewPagerLayoutManager layoutManager =

    (ViewPagerLayoutManager) recyclerView.getLayoutManager();

                    final ViewPagerLayoutManager.OnPageChangeListener onPageChangeListener =

    layoutManager.onPageChangeListener;

                    if (onPageChangeListener !=null) {

    onPageChangeListener.onPageScrollStateChanged(newState);

                    }

    if (newState == RecyclerView.SCROLL_STATE_IDLE &&mScrolled) {

    mScrolled =false;

                        if (!snapToCenter) {

    snapToCenter =true;

                            snapToCenterView(layoutManager, onPageChangeListener);

                        }else {

    snapToCenter =false;

                        }

    }

    }

    @Override

                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

    if (dx !=0 || dy !=0) {

    mScrolled =true;

                    }

    }

    };

    @Override

    public boolean onFling(int velocityX, int velocityY) {

    ViewPagerLayoutManager layoutManager = (ViewPagerLayoutManager)mRecyclerView.getLayoutManager();

        if (layoutManager ==null) {

    return false;

        }

    RecyclerView.Adapter adapter =mRecyclerView.getAdapter();

        if (adapter ==null) {

    return false;

        }

    if (!layoutManager.getInfinite() &&

    (layoutManager.mOffset == layoutManager.getMaxOffset()

    || layoutManager.mOffset == layoutManager.getMinOffset())) {

    return false;

        }

    final int minFlingVelocity =mRecyclerView.getMinFlingVelocity();

        mGravityScroller.fling(0, 0, velocityX, velocityY,

                Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);

        if (layoutManager.mOrientation == ViewPagerLayoutManager.VERTICAL

                && Math.abs(velocityY) > minFlingVelocity) {

    final int currentPosition = layoutManager.getCurrentPositionOffset();

            final int offsetPosition = (int) (mGravityScroller.getFinalY() /

    layoutManager.mInterval / layoutManager.getDistanceRatio());

            ScrollHelper.smoothScrollToPosition(mRecyclerView, layoutManager, layoutManager.getReverseLayout() ?

    -currentPosition - offsetPosition : currentPosition + offsetPosition);

    return true;

        }else if (layoutManager.mOrientation == ViewPagerLayoutManager.HORIZONTAL

                && Math.abs(velocityX) > minFlingVelocity) {

    final int currentPosition = layoutManager.getCurrentPositionOffset();

            final int offsetPosition = (int) (mGravityScroller.getFinalX() /

    layoutManager.mInterval / layoutManager.getDistanceRatio());

            ScrollHelper.smoothScrollToPosition(mRecyclerView, layoutManager, layoutManager.getReverseLayout() ?

    -currentPosition - offsetPosition : currentPosition + offsetPosition);

    return true;

        }

    return true;

    }

    源码:可以看我的上一篇,模仿抖音的效果!!!!!

    public class ScrollHelper {

    /* package */ static void smoothScrollToPosition(RecyclerView recyclerView, ViewPagerLayoutManager viewPagerLayoutManager, int targetPosition) {

    final int delta = viewPagerLayoutManager.getOffsetToPosition(targetPosition);

            if (viewPagerLayoutManager.getOrientation() == ViewPagerLayoutManager.VERTICAL) {

    recyclerView.smoothScrollBy(0, delta);

            }else {

    recyclerView.smoothScrollBy(delta, 0);

            }

    }

    public static void smoothScrollToTargetView(RecyclerView recyclerView, View targetView) {

    final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();

            if (!(layoutManagerinstanceof ViewPagerLayoutManager))return;

            final int targetPosition = ((ViewPagerLayoutManager) layoutManager).getLayoutPositionOfView(targetView);

            smoothScrollToPosition(recyclerView, (ViewPagerLayoutManager) layoutManager, targetPosition);

        }

    }

    /**

    * 可缩放的弧形菜单

    */

    publicclassCircleScaleLayoutManagerextendsViewPagerLayoutManager{

    publicstaticfinalintLEFT=10;

    publicstaticfinalintRIGHT=11;

    publicstaticfinalintTOP=12;

    publicstaticfinalintBOTTOM=13;

    publicstaticfinalintLEFT_ON_TOP=4;

    publicstaticfinalintRIGHT_ON_TOP=5;

    publicstaticfinalintCENTER_ON_TOP=6;

    privateintradius;// 半径

    privateintangleInterval;// 间隔角度

    privatefloatmoveSpeed;

    privatefloatcenterScale;// 中心缩放比

    privatefloatmaxRemoveAngle;

    privatefloatminRemoveAngle;

    privateintgravity;

    privatebooleanflipRotate;

    privateintzAlignment;

    publicCircleScaleLayoutManager(Contextcontext) {

    this(newBuilder(context));

        }

    publicCircleScaleLayoutManager(Contextcontext,intgravity,booleanreverseLayout) {

    this(newBuilder(context).setGravity(gravity).setReverseLayout(reverseLayout));

        }

    publicCircleScaleLayoutManager(Contextcontext,booleanreverseLayout) {

    this(newBuilder(context).setReverseLayout(reverseLayout));

        }

    publicCircleScaleLayoutManager(Builderbuilder) {

    this(builder.context,builder.radius,builder.angleInterval,builder.centerScale,builder.moveSpeed,

    builder.maxRemoveAngle,builder.minRemoveAngle,builder.gravity,builder.zAlignment,

    builder.flipRotate,builder.maxVisibleItemCount,builder.distanceToBottom,builder.reverseLayout);

        }

    privateCircleScaleLayoutManager(Contextcontext,intradius,intangleInterval,floatcenterScale,

    floatmoveSpeed,floatmax,floatmin,intgravity,intzAlignment,

    booleanflipRotate,intmaxVisibleItemCount,intdistanceToBottom,booleanreverseLayout) {

    super(context,HORIZONTAL,reverseLayout);

    setEnableBringCenterToFront(true);

    setMaxVisibleItemCount(maxVisibleItemCount);

    setDistanceToBottom(distanceToBottom);

    this.radius=radius;

    this.angleInterval=angleInterval;

    this.centerScale=centerScale;

    this.moveSpeed=moveSpeed;

    this.maxRemoveAngle=max;

    this.minRemoveAngle=min;

    this.gravity=gravity;

    this.flipRotate=flipRotate;

    this.zAlignment=zAlignment;

        }

    publicintgetRadius() {

    returnradius;

        }

    publicintgetAngleInterval() {

    returnangleInterval;

        }

    publicfloatgetCenterScale() {

    returncenterScale;

        }

    publicfloatgetMoveSpeed() {

    returnmoveSpeed;

        }

    publicfloatgetMaxRemoveAngle() {

    returnmaxRemoveAngle;

        }

    publicfloatgetMinRemoveAngle() {

    returnminRemoveAngle;

        }

    publicintgetGravity() {

    returngravity;

        }

    publicbooleangetFlipRotate() {

    returnflipRotate;

        }

    publicintgetZAlignment() {

    returnzAlignment;

        }

    publicvoidsetRadius(intradius) {

    assertNotInLayoutOrScroll(null);

    if(this.radius==radius)return;

    this.radius=radius;

    removeAllViews();

        }

    publicvoidsetAngleInterval(intangleInterval) {

    assertNotInLayoutOrScroll(null);

    if(this.angleInterval==angleInterval)return;

    this.angleInterval=angleInterval;

    removeAllViews();

        }

    publicvoidsetCenterScale(floatcenterScale) {

    assertNotInLayoutOrScroll(null);

    if(this.centerScale==centerScale)return;

    this.centerScale=centerScale;

    requestLayout();

        }

    publicvoidsetMoveSpeed(floatmoveSpeed) {

    assertNotInLayoutOrScroll(null);

    if(this.moveSpeed==moveSpeed)return;

    this.moveSpeed=moveSpeed;

        }

    publicvoidsetMaxRemoveAngle(floatmaxRemoveAngle) {

    assertNotInLayoutOrScroll(null);

    if(this.maxRemoveAngle==maxRemoveAngle)return;

    this.maxRemoveAngle=maxRemoveAngle;

    requestLayout();

        }

    publicvoidsetMinRemoveAngle(floatminRemoveAngle) {

    assertNotInLayoutOrScroll(null);

    if(this.minRemoveAngle==minRemoveAngle)return;

    this.minRemoveAngle=minRemoveAngle;

    requestLayout();

        }

    @SuppressLint("WrongConstant")

    publicvoidsetGravity(intgravity) {

    assertNotInLayoutOrScroll(null);

    assertGravity(gravity);

    if(this.gravity==gravity)return;

    this.gravity=gravity;

    if(gravity==LEFT||gravity==RIGHT) {

    setOrientation(VERTICAL);

    }else{

    setOrientation(HORIZONTAL);

            }

    requestLayout();

        }

    publicvoidsetFlipRotate(booleanflipRotate) {

    assertNotInLayoutOrScroll(null);

    if(this.flipRotate==flipRotate)return;

    this.flipRotate=flipRotate;

    requestLayout();

        }

    publicvoidsetZAlignment(intzAlignment) {

    assertNotInLayoutOrScroll(null);

    assertZAlignmentState(zAlignment);

    if(this.zAlignment==zAlignment)return;

    this.zAlignment=zAlignment;

    requestLayout();

        }

    @Override

    protectedfloatsetInterval() {

    returnangleInterval;

        }

    @Override

    protectedvoidsetUp() {

    radius=radius==Builder.INVALID_VALUE?mDecoratedMeasurementInOther:radius;

        }

    @Override

    protectedfloatmaxRemoveOffset() {

    returnmaxRemoveAngle;

        }

    @Override

    protectedfloatminRemoveOffset() {

    returnminRemoveAngle;

        }

    @Override

    protectedintcalItemLeft(ViewitemView,floattargetOffset) {

    doublesin=Math.sin(Math.toRadians(90-targetOffset));

    doublecos=Math.cos(Math.toRadians(90-targetOffset));

    switch(gravity) {

    caseLEFT:

    return(int) (radius*sin-radius);

    caseRIGHT:

    return(int) (radius-radius*sin);

    caseTOP:

    caseBOTTOM:

    default:

    return(int) (radius*cos);

            }

        }

    @Override

    protectedintcalItemTop(ViewitemView,floattargetOffset) {

    doublesin=Math.sin(Math.toRadians(90-targetOffset));

    doublecos=Math.cos(Math.toRadians(90-targetOffset));

    switch(gravity) {

    caseLEFT:

    caseRIGHT:

    return(int) (radius*cos);

    caseTOP:

    return(int) (radius*sin-radius);

    caseBOTTOM:

    default:

    return(int) (radius-radius*sin);

            }

        }

    @Override

    protectedvoidsetItemViewProperty(ViewitemView,floattargetOffset) {

    floatscale=1f;

    switch(gravity) {

    caseRIGHT:

    caseTOP:

    // 图片平行 渐变缩放

    if(targetOffset<angleInterval&&targetOffset>-angleInterval) {

    floatdiff=Math.abs(targetOffset);

    scale=diff*(centerScale-1f)/-angleInterval+centerScale;

    // 增加itemView回调

    onPageChangeListener.onViewCentered(diff<5,itemView);

                    }

    break;

    caseLEFT:

    caseBOTTOM:

    default:

    if(flipRotate) {

    itemView.setRotation(360-targetOffset);

    if(targetOffset<angleInterval&&targetOffset>-angleInterval) {

    floatdiff=Math.abs(Math.abs(360-itemView.getRotation()-angleInterval)-angleInterval);

    scale=(centerScale-1f)/-angleInterval*diff+centerScale;

                        }

    }else{

    itemView.setRotation(targetOffset);

    if(targetOffset<angleInterval&&targetOffset>-angleInterval) {

    floatdiff=Math.abs(Math.abs(itemView.getRotation()-angleInterval)-angleInterval);

    scale=(centerScale-1f)/-angleInterval*diff+centerScale;

                        }

                    }

    break;

            }

    itemView.setScaleX(scale);

    itemView.setScaleY(scale);

        }

    @Override

    protectedfloatsetViewElevation(ViewitemView,floattargetOffset) {

    if(zAlignment==LEFT_ON_TOP)

    return(540-targetOffset)/72;

    elseif(zAlignment==RIGHT_ON_TOP)

    return(targetOffset-540)/72;

    else

    return(360-Math.abs(targetOffset))/72;

        }

    @Override

    protectedfloatgetDistanceRatio() {

    if(moveSpeed==0)returnFloat.MAX_VALUE;

    return1/moveSpeed;

        }

    privatestaticvoidassertGravity(intgravity) {

    if(gravity!=LEFT&&gravity!=RIGHT&&gravity!=TOP&&gravity!=BOTTOM) {

    thrownewIllegalArgumentException("gravity must be one of LEFT RIGHT TOP and BOTTOM");

            }

        }

    privatestaticvoidassertZAlignmentState(intzAlignment) {

    if(zAlignment!=LEFT_ON_TOP&&zAlignment!=RIGHT_ON_TOP&&zAlignment!=CENTER_ON_TOP) {

    thrownewIllegalArgumentException("zAlignment must be one of LEFT_ON_TOP RIGHT_ON_TOP and CENTER_ON_TOP");

            }

        }

    publicstaticclassBuilder{

    privatestaticintINTERVAL_ANGLE=30;// The default mInterval angle between each items

    privatestaticfloatDISTANCE_RATIO=10f;// Finger swipe distance divide item rotate angle

    privatestaticfinalfloatSCALE_RATE=1.2f;

    privatestaticintINVALID_VALUE=Integer.MIN_VALUE;

    privateintradius;

    privateintangleInterval;

    privatefloatcenterScale;

    privatefloatmoveSpeed;

    privatefloatmaxRemoveAngle;

    privatefloatminRemoveAngle;

    privatebooleanreverseLayout;

    privateContextcontext;

    privateintgravity;

    privatebooleanflipRotate;

    privateintzAlignment;

    privateintmaxVisibleItemCount;

    privateintdistanceToBottom;

    publicBuilder(Contextcontext) {

    this.context=context;

    radius=INVALID_VALUE;

    angleInterval=INTERVAL_ANGLE;

    centerScale=SCALE_RATE;

    moveSpeed=1/DISTANCE_RATIO;

    maxRemoveAngle=90;

    minRemoveAngle=-90;

    reverseLayout=false;

    flipRotate=false;

    gravity=BOTTOM;

    zAlignment=CENTER_ON_TOP;

    distanceToBottom=ViewPagerLayoutManager.INVALID_SIZE;

    maxVisibleItemCount=ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN;

            }

    publicBuildersetRadius(intradius) {

    this.radius=radius;

    returnthis;

            }

    publicBuildersetAngleInterval(intangleInterval) {

    this.angleInterval=angleInterval;

    returnthis;

            }

    publicBuildersetCenterScale(floatcenterScale) {

    this.centerScale=centerScale;

    returnthis;

            }

    publicBuildersetMoveSpeed(intmoveSpeed) {

    this.moveSpeed=moveSpeed;

    returnthis;

            }

    publicBuildersetMaxRemoveAngle(floatmaxRemoveAngle) {

    this.maxRemoveAngle=maxRemoveAngle;

    returnthis;

            }

    publicBuildersetMinRemoveAngle(floatminRemoveAngle) {

    this.minRemoveAngle=minRemoveAngle;

    returnthis;

            }

    publicBuildersetReverseLayout(booleanreverseLayout) {

    this.reverseLayout=reverseLayout;

    returnthis;

            }

    publicBuildersetGravity(intgravity) {

    assertGravity(gravity);

    this.gravity=gravity;

    returnthis;

            }

    publicBuildersetFlipRotate(booleanflipRotate) {

    this.flipRotate=flipRotate;

    returnthis;

            }

    publicBuildersetZAlignment(intzAlignment) {

    assertZAlignmentState(zAlignment);

    this.zAlignment=zAlignment;

    returnthis;

            }

    publicBuildersetMaxVisibleItemCount(intmaxVisibleItemCount) {

    this.maxVisibleItemCount=maxVisibleItemCount;

    returnthis;

            }

    publicBuildersetDistanceToBottom(intdistanceToBottom) {

    this.distanceToBottom=distanceToBottom;

    returnthis;

            }

    publicCircleScaleLayoutManagerbuild() {

    returnnewCircleScaleLayoutManager(this);

            }

        }

    }

    public static final int DETERMINE_BY_MAX_AND_MIN = -1;

        public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;

        public static final int VERTICAL = OrientationHelper.VERTICAL;

        private static final int DIRECTION_NO_WHERE = -1;

        private static final int DIRECTION_FORWARD =0;

        private static final int DIRECTION_BACKWARD =1;

        protected static final int INVALID_SIZE = Integer.MAX_VALUE;

        private SparseArraypositionCache =new SparseArray<>();

        protected int mDecoratedMeasurement;

        protected int mDecoratedMeasurementInOther;

    demo地址:https://github.com/pengcaihua123456/shennandadao

    相关文章

      网友评论

        本文标题:9.Android RecyclerView 画廊 自定

        本文链接:https://www.haomeiwen.com/subject/jbrpultx.html