自定义RecyclerView实现不固定刻度的刻度尺
程序员文章站
2022-03-02 14:53:19
##不均匀刻度效果图##等比例刻度效果图实现功能目前1、实现类似日期/分类等大小不固定的水平刻度尺效果2、实现标准刻度尺效果3、监听RecyclerView滑动时居中条目4、去掉边缘阴影定义RecyclerViewpublic class CenterRecyclerView extends RecyclerView {//设置RecyclerView的速度 private static final int MAXIMUM_FLING_VELOCITY = 3000;//画...
##不均匀刻度效果图
##等比例刻度效果图
实现功能目前
1、实现类似日期/分类等大小不固定的水平刻度尺效果
2、实现标准刻度尺效果
3、监听RecyclerView滑动时居中条目
4、去掉边缘阴影
定义RecyclerView
public class CenterRecyclerView extends RecyclerView {
//设置RecyclerView的速度
private static final int MAXIMUM_FLING_VELOCITY = 3000;
//画中轴线
private Paint mCenterLinePaint;
private Context context;
private CenterLayoutManager mLayoutManager;
private Paint mTextPaint;
private String text = "";
private String textUnit = "";
private Paint mTextUnitPaint;
private int mWidth;
private int mHeight;
private int mLineStartY;
private int mLineEndY;
private int mTextStartY;
public CenterRecyclerView(@NonNull Context context) {
this(context, null);
}
public CenterRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public CenterRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
this.context = context;
initPaint();
}
public void setTypeface(Typeface typeface) {
mTextPaint.setTypeface(typeface);
mTextUnitPaint.setTypeface(typeface);
}
private void initPaint() {
mCenterLinePaint = new Paint();
mCenterLinePaint.setAntiAlias(true);
mCenterLinePaint.setStrokeWidth(ScreenUtil.dip2px(context, 4));
mCenterLinePaint.setTextAlign(Paint.Align.CENTER);
mCenterLinePaint.setColor(0xff6e9fff);
mTextUnitPaint = new Paint();
mTextUnitPaint.setStyle(Paint.Style.FILL);
mTextUnitPaint.setStrokeWidth(ScreenUtil.dip2px(context, 4));
mTextUnitPaint.setTextSize(ScreenUtil.dip2px(context, 15));
mTextUnitPaint.setColor(Color.parseColor("#DD5F00"));
mTextPaint = new Paint();
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setStrokeWidth(ScreenUtil.dip2px(context, 4));
mTextPaint.setTextSize(ScreenUtil.dip2px(context, 60));
mTextPaint.setColor(Color.parseColor("#DD5F00"));
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
public void addOnScrollListener(@NonNull OnScrollListener listener) {
super.addOnScrollListener(listener);
postInvalidate();
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
}
//获取相关参数
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mWidth = getWidth();
mHeight = getHeight();
int lineHeight = ScreenUtil.dip2px(context, 58);
mLineStartY = mHeight / 2 - lineHeight / 2;
mLineEndY = mHeight / 2 + lineHeight / 2;
mTextStartY = mHeight / 2 - ScreenUtil.dip2px(context, 55);
}
@Override
public void draw(Canvas c) {
super.draw(c);
Log.d("szjjyh", "draw: " + getWidth());
drawCenterLine(c);
drawText(c);
}
//画线
private void drawCenterLine(Canvas canvas) {
canvas.drawLine(mWidth / 2, mLineStartY, mWidth / 2, mLineEndY, mCenterLinePaint);
}
//画字/画单位
private void drawText(Canvas c) {
c.drawText(text, mWidth / 2, mTextStartY, mTextPaint);
if (textUnit != null && textUnit.length() != 0) {
float textWidth = mTextPaint.measureText(text);
c.drawText(textUnit, (mWidth + textWidth) / 2, mTextStartY, mTextUnitPaint);
}
}
public String getText() {
return text;
}
public void setText(String text) {
if (text == null) {
return;
}
this.text = text;
}
public String getTextUnit() {
return textUnit;
}
public void setTextUnit(String textUnit) {
if (textUnit == null) {
return;
}
this.textUnit = textUnit;
}
@Override
public void setAdapter(@Nullable Adapter adapter) {
super.setAdapter(adapter);
}
@Override
public void setLayoutManager(@Nullable LayoutManager layout) {
super.setLayoutManager(layout);
mLayoutManager = (CenterLayoutManager) layout;
}
@Override
public boolean fling(int velocityX, int velocityY) {
velocityX = solveVelocity(velocityX);
velocityY = solveVelocity(velocityY);
return super.fling(velocityX, velocityY);
}
private int solveVelocity(int velocity) {
if (velocity > 0) {
return Math.min(velocity, MAXIMUM_FLING_VELOCITY);
} else {
return Math.max(velocity, -MAXIMUM_FLING_VELOCITY);
}
}
// @Override
// protected float getLeftFadingEdgeStrength() {
// return 0;
// }
}
定义LinearLayoutManager
public class CenterLayoutManager extends LinearLayoutManager {
public CenterLayoutManager(Context context) {
super(context);
}
public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
//计算偏移量自己适配
@Override
public void scrollToPosition(int position) {
scrollToPositionWithOffset(position,-15);
}
@Override
public void scrollToPositionWithOffset(int position, int offset) {
super.scrollToPositionWithOffset(position, offset);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
public void smoothScrollToPosition(RecyclerView recyclerView, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private static class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
//滑动到中间位置
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
//滚动速度设置
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 4;
}
@Override
protected int getVerticalSnapPreference() {
return super.getVerticalSnapPreference();
}
}
}
滑动事件监听
public class CenterScrollListener extends RecyclerView.OnScrollListener {
private CenterLayoutManager mLayoutManager;
RecyclerView recyclerView;
private int mPosition;
private double intScrollState;
private int mFirstItemPosition1;
private int mLastItemPosition1;
private boolean is_Stop;
private String TAG = "CenterScrollListener";
private double is_playSound;
public CenterScrollListener(OnItemCenterScrollistner onItemCenterScrollistner) {
this.onItemCenterScrollistner = onItemCenterScrollistner;
}
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
init(recyclerView);
intScrollState = newState;
is_Stop = false;
if (intScrollState == RecyclerView.SCROLL_STATE_IDLE) {
Log.e(TAG, "onScrollStateChanged: 11111:"+mPosition);
CeterScroll(0, mPosition);
}
}
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
init(recyclerView);
int x = Math.abs(dx);
if (!is_Stop && x <= 1) {
is_Stop = true;
if (dx >= 0) {
mPosition = (mFirstItemPosition1 + mLastItemPosition1) / 2;
View childAt = mLayoutManager.findViewByPosition(mPosition);
if (childAt.getLeft() < ScreenUtil.getScreenWidth(recyclerView.getContext()) / 2) {
mPosition = mPosition + 1;
}
Log.e(TAG, "111111: w:" + childAt.getWidth() + " :l:" +
childAt.getLeft() + " :r:" + childAt.getRight());
} else {
mPosition = (mFirstItemPosition1 + mLastItemPosition1) / 2;
View childAt = mLayoutManager.findViewByPosition(mPosition);
if (childAt.getLeft() > ScreenUtil.getScreenWidth(recyclerView.getContext()) / 2) {
mPosition = mPosition - 1;
}
}
}
CeterScroll(x, mPosition);
}
//事件监听
private void init(@NonNull RecyclerView recyclerView) {
this.recyclerView = recyclerView;
if (mLayoutManager == null) {
mLayoutManager = (CenterLayoutManager) recyclerView.getLayoutManager();
}
int firstItemPosition = mLayoutManager.findFirstVisibleItemPosition();
int lastItemPosition = mLayoutManager.findLastVisibleItemPosition();
mFirstItemPosition1 = mLayoutManager.findFirstCompletelyVisibleItemPosition();
mLastItemPosition1 = mLayoutManager.findLastCompletelyVisibleItemPosition();
mPosition = (mFirstItemPosition1 + mLastItemPosition1) / 2;
if (is_playSound != mPosition) {
is_playSound = mPosition;
int count = mLayoutManager.getItemCount();
// soundpool.play(soundmap.get(1), 1, 1, 0, 0, 1);
if (onItemCenterScrollistner != null) {
//中间条目事件监听
onItemCenterScrollistner.onItemCenterScrollistner(mLastItemPosition1, mPosition,count);
}
}
//目前由于要实现灰色条目当条目间距为10dp,屏幕宽度360时不能继续滑动
if (mPosition <= 18) {
CeterScroll(0, 18);
}
}
//速度变小时自动滚动到中间位置
private void CeterScroll(int dx, int position) {
if ((intScrollState == RecyclerView.SCROLL_STATE_SETTLING || intScrollState
== RecyclerView.SCROLL_STATE_IDLE) && Math.abs(dx) <= 1) {
mLayoutManager.smoothScrollToPosition(recyclerView, position);
}
}
OnItemCenterScrollistner onItemCenterScrollistner;
public void setOnItemCenterScrollistner(OnItemCenterScrollistner onItemCenterScrollistner) {
this.onItemCenterScrollistner = onItemCenterScrollistner;
}
public interface OnItemCenterScrollistner {
void onItemCenterScrollistner(int lastItemPosition1, int position, int count);
}
adpater实现
public class DateAdapter extends BaseRecyclerAdapter<CalendarDateBean> {
private static final int layoutId = R.layout.view_item_date;
public DateAdapter(Context context, List<CalendarDateBean> datas) {
super(context, datas, layoutId);
}
@Override
protected void bindData(BaseViewHolder holder, CalendarDateBean data, int position) {
if (data.getDay() == 1) {
//R.id.tv_1为线需要居中否则和中轴线不会完全对称 R.id.tv_2为大刻度文字
holder.getView(R.id.tv_1).setScaleX(2F);
holder.setText(R.id.tv_2, data.getMonth() + "月");
holder.getView(R.id.tv_2).setVisibility(View.VISIBLE);
holder.getView(R.id.tv_1).setBackgroundColor(Color.parseColor("#ffffff"));
} else if (data.getDay() ==-1){
holder.getView(R.id.tv_1).setScaleX(1F);
holder.getView(R.id.tv_2).setVisibility(View.GONE);
holder.getView(R.id.tv_1).setBackgroundColor(Color.parseColor("#222222"));
}else {
holder.getView(R.id.tv_1).setScaleX(1F);
holder.getView(R.id.tv_2).setVisibility(View.GONE);
holder.getView(R.id.tv_1).setBackgroundColor(Color.parseColor("#ffffff"));
}
}
}
activity 加载view展示
private void initRecyclerView() {
//此处试配时注意item10dp 宽度360 计算发放 360/10/2得到记得适配
for (int i = 0; i < 18; i++) {
TimeBean timeBean = new TimeBean();
mList.add(timeBean);
}
for (int i = 0; i < 1440; i++) {
int minute = i % 60;
int hour = i / 60;
if (CalendarUtil.getHourTime()==hour&&CalendarUtil.getMinuteTime()==minute){
mPostion = i;
}
TimeBean timeBean = new TimeBean();
timeBean.setHour(hour);
timeBean.setMinute(minute);
timeBean.setTimeDate(CalendarUtil.getHourToMinute(hour,minute));
mList.add(timeBean);
}
for (int i = 0; i < 18; i++) {
TimeBean timeBean = new TimeBean();
// timeBean.setMinute(-1);
mList.add(timeBean);
}
rv_data = findViewById(R.id.rv_data);
mAdapter = new TimeAdapter(this, mList);
rv_data.setAdapter(mAdapter);
//设置字体
rv_data.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/dincond_boldalternate.ttf"));
CenterLayoutManager layoutManager = new CenterLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
rv_data.setLayoutManager(layoutManager);
rv_data.scrollToPosition(mPostion);
rv_data.addOnScrollListener(new CenterScrollListener((lastItemPosition, position,count) -> {
//更新文本和单位
rv_data.setText(mList.get(position).getTimeDate());
if (mList.get(position).getHour()>12){
rv_data.setTextUnit("PM");
}else {
rv_data.setTextUnit("AM");
}
}));
}
实现了基本代码全部写了
本文地址:https://blog.csdn.net/qq_34541276/article/details/107354439
上一篇: 小白的25天CTF征程