各位看官,下面是效果图(自己手残打了一下码),请先过目:
简单的说一下效果图,横向来区分的话可以把UI图分为三部分【左边是轮盘 , 中间是弧形列表 也是一级菜单 , 右边是列表是二级菜单(不重要就没有放图)】:
要求:
好的、需求很明确,一级菜单弧形列表可滑可点自动选中,轮盘跟随旋转;
代码已上传: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;
}
这样通过改变内边距的方式也可以实现弧形列表;
布局这种小儿科的内容就不贴出来了,下面是弧形列表实现后的效果;
Item的View就只写了一个TextView , 看着比较粗糙;
下一篇:滑动后自动选中请移步:Android 弧形列表转盘的实现(二),列表自动选中;RecyclerView滑动后自动选中居中的条目,RecyclerView实现WheelView效果;