参考自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);
}
}