欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-06-16 10:27:49
##不均匀刻度效果图##等比例刻度效果图实现功能目前1、实现类似日期/分类等大小不固定的水平刻度尺效果2、实现标准刻度尺效果3、监听RecyclerView滑动时居中条目4、去掉边缘阴影定义RecyclerViewpublic class CenterRecyclerView extends RecyclerView {//设置RecyclerView的速度 private static final int MAXIMUM_FLING_VELOCITY = 3000;//画...

##不均匀刻度效果图
自定义RecyclerView实现不固定刻度的刻度尺
##等比例刻度效果图
自定义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");
            }
        }));

    }

实现了基本代码全部写了

本文地址:https://blog.csdn.net/qq_34541276/article/details/107354439

相关标签: android app