自定义RecyclerView实现不固定刻度的刻度尺

##不均匀刻度效果图
日期
##等比例刻度效果图
时间

实现功能目前

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");
            }
        }));

    }

实现了基本代码全部写了

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值