Android 弧形列表转盘的实现(一),弧形列表;

各位看官,下面是效果图(自己手残打了一下码),请先过目:

简单的说一下效果图,横向来区分的话可以把UI图分为三部分【左边是轮盘 , 中间是弧形列表 也是一级菜单 , 右边是列表是二级菜单(不重要就没有放图)】:

要求:

  1. 实现一个围绕轮盘的弧形列表;
  2. 弧形列表滑动后自动选中居中的条目,然后更新右边的二级菜单;
  3. 弧形列表条目点击后自动滑动到点击的条目并选中,然后更新右边的二级菜单;
  4. 弧形列表所有条目都可以选择;
  5. 左边的轮盘跟随弧形列表旋转;

好的、需求很明确,一级菜单弧形列表可滑可点自动选中,轮盘跟随旋转;

代码已上传:CSDN:https://download.csdn.net/download/qq_35605213/12470655

Github:https://github.com/CuiChenbo/ArcSelectList , 欢迎Star

APP下载地址:http://d.7short.com/ArcSelectList

第一步:先实现弧形列表;

然后开始找轮子,各大网站找个一圈都没有发现类似的开源框架;发现这个'https://github.com/kHRYSTAL/CircleRecyclerView' 可以实现弧形列表,下载下来试了一下有些差别,不能所有的条目都选中(第一个条目拉不下来),未选中的没有点击事件;后续又找了几个类似的文章,跟效果都有点差别,无奈只能自己写了;

实现弧形列表的第一想法时自定义RecyclerView的LayoutManager,后来参考了一下这篇文章(https://github.com/dkmeteor/CircleList)用设置偏移量实现RecyclerView弧形列表;

实现方式一 ,矩阵偏移:

1、先自定义Layout实现偏移 , RecyclerView的Item布局的根布局使用这个Layout;

public class MatrixTranslateLayout extends LinearLayout {
    private int parentHeight = 0;
    private int topOffset = 0;
    public MatrixTranslateLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setParentHeight(int height) {
        parentHeight = height;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();
        if (topOffset == 0) {
            topOffset = getHeight() / 2;
        }
        int top = getTop()+topOffset;

       float tran = calculateTranslate(top , parentHeight);

        Matrix m = canvas.getMatrix();
        m.setTranslate(tran,0);
        canvas.concat(m);
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }


    private float calculateTranslate(int top, int h) {
        float result = 0f;
        int hh = h/2;
        result = Math.abs(top - hh)*-1;
        return (float) (result/2);
    }
}

2、RecyclerView的Adapter填充布局时设置矩阵偏移量;

class MAdapter extends RecyclerView.Adapter {
        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new MAdapter.VH(LayoutInflater.from(ArcActivity.this).inflate(R.layout.item_arc, parent, false));
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            MAdapter.VH vh = (MAdapter.VH) holder;
            ((MatrixTranslateLayout) vh.itemView).setParentHeight(recyclerView.getHeight());
            vh.tv.setText(mDatas.get(position));
            final int fp = position;
            vh.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    TUtils.show(ArcActivity.this, "点击" +mDatas.get(fp));
                }
            });
        }

        @Override
        public int getItemCount() {
            return mDatas.size();
        }

        class VH extends RecyclerView.ViewHolder {

            public TextView tv;

            public VH(@NonNull View itemView) {
                super(itemView);
                tv = itemView.findViewById(R.id.tv);
            }
        }
    }

切记:要等布局完全加载后再设置Adapter , 不然会拿不到RecyclerView的高度;

recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                findView();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            }
        });

3、当RecyclerView滑动时重新调整矩阵偏移量;

 private void findView() {
        mAdapter = new MAdapter();
        recyclerView.setAdapter(mAdapter);

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                for (int i = 0; i < recyclerView.getChildCount(); i++) {
                    recyclerView.getChildAt(i).invalidate();
                }
            }
        });

    }

这样一个弧形RecyclerView就实现了;

实现方式二 ,内边距偏移:

不需要自定义Layout , 只需要改变Item根布局的PaddingLift即可;

根据方式一的思路换了一个实现方式,具体看代码:

recyclerView.setLayoutManager(new LinearLayoutManager(this));

        recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                recyclerViewHeight = recyclerView.getHeight();
                setData();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            }
        });
    private void setData() {
        recyclerView.setAdapter(new RecyclerView.Adapter() {
            @NonNull
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                return new VH(LayoutInflater.from(PadingArcActivity.this).inflate( R.layout.item_pading,parent,false));
            }

            @Override
            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
                VH vh = (VH) holder;
                RelativeLayout mv = (RelativeLayout) vh.itemView;
                mv.setPadding(calculateTranslate(mv.getTop() , recyclerViewHeight) , 0 ,0 ,0 );
                vh.tv.setText("你好"+position+"索引");
                final int fp = position;
                vh.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        TUtils.show(PadingArcActivity.this , "你好"+fp+"索引");
                    }
                });
            }

            @Override
            public int getItemCount() {
                return 100;
            }

            class VH extends RecyclerView.ViewHolder{

                public TextView tv;
                public VH(@NonNull View itemView) {
                    super(itemView);
                    tv = itemView.findViewById(R.id.tv);
                }
            }
        });

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                for (int i = 0; i < recyclerView.getChildCount(); i++) {
                    int pad =  calculateTranslate(recyclerView.getChildAt(i).getTop() , recyclerViewHeight);
                    recyclerView.getChildAt(i).setPadding( pad, 0 ,0 ,0 );
                }
            }
        });
    }

    private int calculateTranslate(int top, int h) {
        int result = 0;
        h = h - UiUtils.dip2px(this , 60); //减去当前控件的高度,(60是已知当前Item的高度)
        int hh = h/2;
        result = Math.abs(hh - top);
        result = hh - result;
        return result/2;
    }

这样通过改变内边距的方式也可以实现弧形列表;

布局这种小儿科的内容就不贴出来了,下面是弧形列表实现后的效果;

 

Android 弧形列表转盘的实现(一),弧形列表;_第1张图片

 

Item的View就只写了一个TextView , 看着比较粗糙;

下一篇:滑动后自动选中请移步:Android 弧形列表转盘的实现(二),列表自动选中;RecyclerView滑动后自动选中居中的条目,RecyclerView实现WheelView效果;

你可能感兴趣的:(Android)