优化版:时间滚轮控件的绘制[ref: vonchenchen1]

参考自CSDN @vonchenchen1 — Android自定义控件:时间滚轮控件的绘制
下面用chatgpt 4 进行了优化。
抄代码前用chatgpt 优化一下还是很棒的,谢谢vonchenchen1

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.core.content.ContextCompat;

import java.util.ArrayList;

public class CustomWheelView extends View {

    public static final String TAG = "TimePicker";

    private Context context;

    private int viewHeight;
    private int viewWidth;
    private int centerItemHeight;
    private int centerY;

    private float lastDownY;
    private float moveDistanceY = 0;
    private int currentDataIndex = 0;
    private Paint textPaint;
    private Paint linePaint;
    private int maxTextSize;
    private float gapRatio = 0.7f;
    private boolean isTouchEnable = true;
    private boolean isTouchDownEnable = true;
    private boolean isTouchUpEnable = true;

    private ArrayList<String> dataList = new ArrayList<>();

    public CustomWheelView(Context context) {
        super(context);
        init(context);
    }

    public CustomWheelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        this.context = context;

        initData();

        textPaint = new Paint();
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setColor(ContextCompat.getColor(context, R.color.colorPrimary));

        linePaint = new Paint();
        linePaint.setStyle(Paint.Style.FILL);
        linePaint.setTextAlign(Paint.Align.CENTER);
        linePaint.setColor(ContextCompat.getColor(context, R.color.colorPrimary));
    }

    private void initData() {
        for (int i = 0; i < 24; i++) {
            dataList.add(i + "");
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        viewHeight = getMeasuredHeight();
        viewWidth = getMeasuredWidth();

        centerY = viewHeight / 2;
        maxTextSize = viewHeight / 8;
        centerItemHeight = viewHeight / 4;
        gapRatio = 0.7f;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (isTouchEnable) {
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    onActionDown(event);
                    break;
                case MotionEvent.ACTION_MOVE:
                    onActionMove(event);
                    break;
                case MotionEvent.ACTION_UP:
                    onActionUp(event);
                    break;
            }
        }

        return true;
    }

    private void onActionDown(MotionEvent event) {
        lastDownY = event.getY();
    }

    private void onActionMove(MotionEvent event) {
        float currentY = event.getY();
        float diff = currentY - lastDownY;

        if (isTouchUpEnable && isTouchDownEnable) {
            moveDistanceY += diff;
        } else if (!isTouchUpEnable && isTouchDownEnable) {
            if (diff > 0) {
                moveDistanceY += diff;
                isTouchUpEnable = true;
            }
        } else if (isTouchUpEnable && !isTouchDownEnable) {
            if (diff < 0) {
                moveDistanceY += diff;
                isTouchDownEnable = true;
            }
        }
        lastDownY = currentY;
        invalidate();
    }

    private void onActionUp(MotionEvent event) {
        returnBack(moveDistanceY, 0);
    }

    private void drawText(Canvas canvas, int currentIndex, int position) {
        float length = centerY + moveDistanceY;
        float baseY;
        Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
        int diff = (fontMetricsInt.bottom + fontMetricsInt.top) / 2;

        if (position == 0) {
            float scale = getScale((int) moveDistanceY);
            textPaint.setTextSize((float) (maxTextSize * scale));
            baseY = length - diff;
            canvas.drawText(dataList.get(currentIndex), viewWidth / 2, baseY, textPaint);

            if (moveDistanceY > centerItemHeight / 2) {
                if (currentDataIndex > 0) {
                    currentDataIndex--;
                } else {
                    isTouchDownEnable = false;
                }
                moveDistanceY = 0;
            } else if (moveDistanceY < -centerItemHeight / 2) {
                if (currentDataIndex < dataList.size() - 1) {
                    currentDataIndex++;
                } else {
                    isTouchUpEnable = false;
                }
                moveDistanceY = 0;
            }
        } else {
            int realIndex = currentIndex + position;

            if (realIndex >= 0 && realIndex < dataList.size()) {
                length = length + centerItemHeight * gapRatio * position;

                float scale = getScale((int) length - centerY);
                textPaint.setTextSize((float) (maxTextSize * scale));
                baseY = length - diff;

                canvas.drawText(dataList.get(realIndex), viewWidth / 2, baseY, textPaint);
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = -3; i <= 3; i++) {
            drawText(canvas, currentDataIndex, i);
        }
        canvas.drawLine(0, centerY - centerItemHeight / 2, viewWidth, centerY - centerItemHeight / 2, linePaint);
        canvas.drawLine(0, centerY + centerItemHeight / 2, viewWidth, centerY + centerItemHeight / 2, linePaint);
    }

    private float getScale(int lengthToCenter) {
        float ret = (float) (1 - Math.pow(((float) lengthToCenter) / centerY, 2));
        if (ret < 0) {
            ret = 0;
        }
        return ret;
    }

    private void returnBack(float start, float end) {
        isTouchEnable = false;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
        valueAnimator.setDuration(100);
        valueAnimator.addUpdateListener(valueAnimator1 -> {
            moveDistanceY = (float) valueAnimator1.getAnimatedValue();
            if (Math.abs(moveDistanceY) <= 3) {
                moveDistanceY = 0;
            }
            invalidate();
        });

        valueAnimator.addListener(new ValueAnimator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isTouchEnable = true;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        valueAnimator.start();
    }

    public String getTimeData() {
        return dataList.get(currentDataIndex);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值