自定义控件Android应用开发那些事Android开发经验谈

LayoutManager学习(三)实现一个横向的弧形滑动列表

2019-06-18  本文已影响2人  刘景昌

一样先上最总效果图


5s.gif

实现的是一个弧形横向滑动的列表
实现过程:离不开的LayoutManager实现三部曲
1.继承RecyclerView.LayoutManager
2.重写onLayoutChildren来添加子View 完成一个列表的静态界面
3.重写scrollVerticallyBy来实现竖向滚动 是列表可以滚动
具体实现:

创建一个条目类

为了能使每个View都具有自己的属性 所以一样为每个条目创建自己的bean
我们先分析一下所需要的属性

public class ArcViewBean {
    //距离左边的距离
    private int left;
    //距离下面的距离
    private int bottom;
    //缩放大小
    private float scaleXY = 1.0f;
    //旋转角度
    private float rotate;
    public float getScaleXY() {
        if(rotate>90||rotate<-90){
            return 0.5f;
        }else{
            return 0.5f +(90-Math.abs(rotate))/90;
        }
    }
}

这里面每个条目都需要四个属性来判断换显示 分别是:左边距 下边距 旋转角度 缩放并在内部定义缩放规则

实现静态界面

(1)创建所有要显示View的Bean

   private ArrayList<ArcViewBean> createItemViewInfoList() {
        ArrayList<ArcViewBean> arcViewBeans = new ArrayList<>();
        for (int i = 0; i < getItemCount(); i++) {
            ArcViewBean arcViewBean = new ArcViewBean();
            float rotate = mRotate + i * intervalAngle;
            arcViewBean.setRotate(rotate);
            arcViewBean.setLeft(startLeft + calLeftPosition(rotate));
            arcViewBean.setBottom(startBottom - calBottomPosition(rotate));
            arcViewBeans.add(arcViewBean);
        }
        return arcViewBeans;
    }

(2)移除View放入缓存中并绘制View

//在布局之前,将所有的子View先Detach掉,放入到Scrap缓存中
     detachAndScrapAttachedViews(recycler);

绘制View

    private void drawView(RecyclerView.Recycler recycler, RecyclerView.State state, ArrayList<ArcViewBean> arcViewBeans) {
        if (state.isPreLayout()) return;
        for (int i = 0; i < getItemCount(); i++) {
            ArcViewBean arcViewBean = arcViewBeans.get(i);
            if (arcViewBean.getRotate() <= maxRemoveDegree
                    && arcViewBean.getRotate() >= minRemoveDegree) {
                View scrap = recycler.getViewForPosition(i);
                measureChildWithMargins(scrap, 0, 0);
                addView(scrap);
                int left = arcViewBean.getLeft();
                int bottom = arcViewBean.getBottom();
                scrap.setRotation(arcViewBean.getRotate());
                layoutDecorated(scrap, left, bottom,
                        left + mDecoratedChildWidth, bottom + mDecoratedChildHeight);
                scrap.setScaleX(arcViewBean.getScaleXY());
                scrap.setScaleY(arcViewBean.getScaleXY());
            }
        }
    }

这样就显示了静态界面

让界面可以滑动起来

因为是横向滑动

    @Override
    public boolean canScrollHorizontally() {
        return true;
    }

然后 设置一个横向滑动与角度的转换比例 DISTANCE_RATIO 让我们可以计算出滑动的角度

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int willScroll = dx;

        //每个item x方向上的移动距离
        float theta = dx / DISTANCE_RATIO;
        float targetRotate = offsetRotate + theta;

        //目标角度
        if (targetRotate < 0) {
            willScroll = (int) (-offsetRotate * DISTANCE_RATIO);
        } else if (targetRotate > getMaxOffsetDegree()) {
            willScroll = (int) ((getMaxOffsetDegree() - offsetRotate) * DISTANCE_RATIO);
        }
        theta = willScroll / DISTANCE_RATIO;

        //当前移动的总角度
        offsetRotate += theta;
        layoutChildView(recycler, state);
        return willScroll;
    }

计算完以后只需要子设置的时候 这样修改就可以滑动起来了

 float rotate = mRotate + i * intervalAngle - offsetRotate;

demo Github地址 :https://github.com/525642022/LayoutManagerTest

上一篇 下一篇

猜你喜欢

热点阅读