
效果圖.png
分析設(shè)計
從圖上可以看出,需要實現(xiàn)一個垂直的進度條(VerticalSeekbar),該進度條需要包含以下三個部分:
- 進度條
進度條為圓角、漸變背景色效果。 - 可拖拽圓點
圓點需要繪制陰影(shadow)效果或直接根據(jù)UI提供的圖片繪制 - 進度指示游標
根據(jù)拖拽進度展示,拖拽結(jié)束隱藏。
實現(xiàn)
這里通過自定義View來實現(xiàn)上述效果
代碼如下:
public class VerticalSeekBar extends View {
private static final int MAX_VALUE = 100;
private static final int MIN_VALUE = 0;
private int startColor = Color.parseColor("#FAD0C4");
private int middleColor = Color.parseColor("#FAD0C4");
private int endColor = Color.parseColor("#FFD1FF");
private int thumbColor = Color.WHITE;
private final int[] colorArray = {startColor, middleColor, endColor};
private float x, y;
private float mRadius;
private float progress;
private float sLeft, sTop, sRight, sBottom;
private float sWidth, sHeight;
private float shadowWidth;
private final Paint paintPb = new Paint();
private final RectF rectBlackBg = new RectF();
private final Paint thumbPaint = new Paint();
protected OnStateChangeListener onStateChangeListener;
public VerticalSeekBar(Context context) {
this(context, null);
init();
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
int h = getMeasuredHeight();
int w = getMeasuredWidth();
shadowWidth = getResources().getDimension(R.dimen.common_measure_2dp);
mRadius = (w - shadowWidth) / 2F;
sLeft = w * 0.25f; // 背景左邊緣坐標
sRight = w * 0.75f;// 背景右邊緣坐標
sTop = 0;
sBottom = h;
sWidth = sRight - sLeft; // 背景寬度
sHeight = sBottom - sTop; // 背景高度
x = (float) w / 2;//圓心的x坐標
y = (float) (1 - 0.01 * progress) * sHeight;//圓心y坐標
// init paint
thumbPaint.setAntiAlias(true);
thumbPaint.setStyle(Paint.Style.FILL);
thumbPaint.setColor(thumbColor);
// 添加陰影效果
thumbPaint.setShadowLayer(shadowWidth, 0, 0, Color.GRAY);
rectBlackBg.set(sLeft, sTop, sRight, sBottom);
paintPb.setAntiAlias(true);
paintPb.setStyle(Paint.Style.FILL);
}
public void setColor(int startColor, int middleColor, int endColor, int thumbColor, int thumbBorderColor) {
this.startColor = startColor;
this.middleColor = middleColor;
this.endColor = endColor;
this.thumbColor = thumbColor;
colorArray[0] = startColor;
colorArray[1] = middleColor;
colorArray[2] = endColor;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBackground(canvas);
drawCircle(canvas);
paintPb.reset();
}
private void drawBackground(Canvas canvas) {
// 設(shè)置渲染器
LinearGradient linearGradient = new LinearGradient(sLeft, sTop, sWidth, sHeight, colorArray, null, Shader.TileMode.MIRROR);
paintPb.setShader(linearGradient);
canvas.drawRoundRect(rectBlackBg, sWidth / 2, sWidth / 2, paintPb);
}
private void drawCircle(Canvas canvas) {
y = Math.max(y, mRadius);// 判斷thumb邊界
y = Math.min(y, sHeight - mRadius);
canvas.drawCircle(x, y, mRadius, thumbPaint);
}
float indicatorOffset = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
this.y = event.getY();
progress = (sHeight - y) / sHeight * MAX_VALUE;
if (progress < MIN_VALUE) {
this.progress = MIN_VALUE;
} else if (progress > MAX_VALUE) {
this.progress = MAX_VALUE;
}
indicatorOffset = sHeight / MAX_VALUE * progress - mRadius * 1.5F;
indicatorOffset = indicatorOffset < 0 ? 0 : (Math.min(indicatorOffset, sHeight - mRadius * 2));
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (onStateChangeListener != null) {
onStateChangeListener.onStartTouch(this);
}
break;
case MotionEvent.ACTION_UP:
if (onStateChangeListener != null) {
onStateChangeListener.onStopTrackingTouch(this, progress);
}
break;
case MotionEvent.ACTION_MOVE:
if (onStateChangeListener != null) {
onStateChangeListener.onStateChangeListener(this, progress, indicatorOffset);
}
setProgress(progress);
this.invalidate();
break;
}
return true;
}
public interface OnStateChangeListener {
void onStartTouch(View view);
void onStateChangeListener(View view, float progress, float indicatorOffset);
void onStopTrackingTouch(View view, float progress);
}
public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
this.onStateChangeListener = onStateChangeListener;
}
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
}