界面主要是通过GridLayoutManager设置每行显示两个item;
mRecyclerView = (MyRecyclerView) rootView.findViewById(R.id.id_recyclerview_grid);
mAppAddBtn = (ImageView) rootView.findViewById(R.id.app_list_add);
mManager = new GridLayoutManager(getActivity().getBaseContext(), 2);
mRecyclerView.setLayoutManager(mManager);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(this);
mAdapter.setOnItemLongClickListener(this);此处就不做介绍了,本文主要是讲在RecyclerView界面右侧加上弧形滚动条原理:自定义RecyclerView,继承RecyclerView,重写onDraw方法,在onDraw中画出滚动条,通过adapter中getItemCount()方法获得总的item数目来决定滚动条移动部分的长度,
优点: 借助RecyclerView的刷新来刷新滚动条位置,不用自己去做大量的刷新,相比于单独定义view可优化部分性能;代码实现:public class MyRecyclerView extends RecyclerView {
private static final String TAG = "RecyclerView";
int mArcLength = 0;
private GridLayoutManager mLayoutManager;
private Paint mBgArcPaint;
private Paint mArcPaint;
private Paint mCirclePaint;
private Paint mBgCirclePaint;
private final int START_ANGLE = 320;
private final int SWEEP_ANGLE = 80;
private final int PADDING =12;
private boolean mIndicatorVisible = false; // 是否显示滚动条
private int mVisibleItemCount = 0;
private Handler mHandler = new Handler();
private int mYscroll = 0;
private MyAdapter mAdapter;
private int mItemHeight = 0;
private float mStrokeWidth = 6;
private int topBottomPadding = 30+40 ;
public MyRecyclerView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public MyRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
/** *定义画笔样式 **/
private void init() {
mBgArcPaint = new Paint();
mBgArcPaint.setAntiAlias(true);
mBgArcPaint.setColor(Color.GRAY);
mBgArcPaint.setStrokeWidth(mStrokeWidth);
mBgArcPaint.setStyle(Style.STROKE); mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setColor(Color.WHITE);
mArcPaint.setStrokeWidth(mStrokeWidth);
mArcPaint.setStyle(Style.STROKE);
// setOnScrollListener(mOnScrollListener);
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(Color.WHITE);
mBgCirclePaint = new Paint();
mBgCirclePaint.setAntiAlias(true);
mBgCirclePaint.setColor(Color.GRAY);
setOnScrollListener(mOnScrollListener);
}
public void clear() {
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
invalidate();
}
@Override
public void draw(Canvas arg0) {
// TODO Auto-generated method stub
super.draw(arg0);
}
@Override
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (mIndicatorVisible) {
int width = getWidth();
int height = getHeight();
int diameter = Math.max(width, height)-PADDING;//diameter should < 200
int count = getAdapter().getItemCount();
int first = mLayoutManager.findFirstVisibleItemPosition();
int last = mLayoutManager.findLastVisibleItemPosition();
View v = mLayoutManager.getChildAt(first);
if (v != null) {
mItemHeight = v.getHeight();
}
if (mVisibleItemCount == 0) {
mVisibleItemCount = last - first;
}
Log.e(TAG,"------mItemHeight="+mItemHeight+", width = "+width+",height="+height);
int totalHeight = mItemHeight * (mAdapter.getItemCount()/mLayoutManager.getSpanCount()+mAdapter.getItemCount()%mLayoutManager.getSpanCount())+ topBottomPadding;
float offsetAngle = 0;
float sweepAngle = (height * SWEEP_ANGLE / totalHeight);
if (totalHeight != 0) {
offsetAngle = (SWEEP_ANGLE * ((float) mYscroll) / totalHeight);
} else {
offsetAngle = (SWEEP_ANGLE * ((float) first) / count);
}
RectF rect = new RectF((width - diameter) / 2,
(height - diameter) / 2, (width + diameter) / 2,
(height + diameter) / 2);
canvas.drawCircle(
(float) (width / 2 + diameter/ 2* Math.cos((START_ANGLE) * Math.PI/ 180)),
(float) (height / 2 + diameter/ 2* Math.sin((START_ANGLE) * Math.PI/ 180)), mStrokeWidth / 2, mBgCirclePaint);
canvas.drawArc(rect, START_ANGLE, SWEEP_ANGLE, false, mBgArcPaint);
canvas.drawCircle((float) (width / 2 + diameter/ 2* Math.cos((START_ANGLE + SWEEP_ANGLE) * Math.PI/ 180)),
(float) (height / 2 + diameter/ 2* Math.sin((START_ANGLE + SWEEP_ANGLE) * Math.PI/ 180)),
mStrokeWidth / 2, mBgCirclePaint);
RectF rect2 = new RectF((width - diameter) / 2,
(height - diameter) / 2, (width + diameter) / 2,
(height + diameter) / 2);
Log.d(TAG, "-------sweepAngle=" + sweepAngle + ",offsetAngle="+ offsetAngle);
canvas.drawCircle(
(float) (width / 2 + diameter/ 2
* Math.cos((START_ANGLE + offsetAngle) * Math.PI
/ 180)),
(float) (height / 2 + diameter
/ 2
* Math.sin((START_ANGLE + offsetAngle) * Math.PI
/ 180)), mStrokeWidth / 2, mCirclePaint);
canvas.drawArc(rect2, START_ANGLE + offsetAngle, sweepAngle, false,
mArcPaint);
canvas.drawCircle(
(float) (width / 2 + diameter
/ 2
* Math.cos((START_ANGLE + offsetAngle+sweepAngle) * Math.PI
/ 180)),
(float) (height / 2 + diameter
/ 2
* Math.sin((START_ANGLE + offsetAngle+sweepAngle) * Math.PI
/ 180)), mStrokeWidth / 2, mCirclePaint);
} else { Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); canvas.drawPaint(paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC)); } } @Override public void setLayoutManager(LayoutManager layout) { // TODO Auto-generated method stub super.setLayoutManager(layout); if (mLayoutManager != layout) { // mLayoutManager = (LinearLayoutManager) layout; mLayoutManager = (GridLayoutManager) layout; } }
@Override protected void onAttachedToWindow() { // TODO Auto-generated method stub super.onAttachedToWindow(); if (getAdapter() != null) { Log.e(TAG, "-----" + getAdapter().getItemCount()); } } Runnable mRun = new Runnable() { public void run() { mIndicatorVisible = false; invalidate(); } }; @Override public boolean onTouchEvent(MotionEvent arg0) { // TODO Auto-generated method stub int action = arg0.getAction(); if (action == MotionEvent.ACTION_MOVE) { mIndicatorVisible = true; } else if (action == MotionEvent.ACTION_UP) { mHandler.removeCallbacks(mRun); mHandler.postDelayed(mRun, 3000); } return super.onTouchEvent(arg0); }
@Override public void setAdapter(Adapter adapter) { // TODO Auto-generated method stub super.setAdapter(adapter); mAdapter = (MyAdapter) adapter; } private RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { // TODO Auto-generated method stub super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // TODO Auto-generated method stub super.onScrolled(recyclerView, dx, dy); mYscroll = mYscroll + dy; } }; }
这篇博客主要介绍如何在RecyclerView的右侧添加一个弧形滚动条。通过自定义RecyclerView,重写onDraw方法,利用GridLayoutManager每行显示两个item,并结合Adapter的数据获取总item数,动态计算并绘制滚动条的位置。这种方法利用RecyclerView的刷新机制,优化了性能。





