一、概述
这是一个带悬浮文字的水平SeekBar,可以设置手指按下显示,还是一直显示悬浮文字。本来想在网上找一个框架,但是想改成自己需求的样子都差点,可能自己没搞清楚API。最后自己写了个功能简单的,有需要的拿走自己修改,废话不多说,直接上代码。
二、内容
1、效果图
2、代码
package com.yang.mytest.util; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; /** * Created by yp on 2018-03-26. */ public class MyHorizontalSeekBar extends View { private Context context; /** 进度条宽度 */ private float barWidth = getTextSizeDip(4); /** view的宽 */ private int width; /** view的高 */ private int height; /** seekbar总值 */ private int maxProgress = 100; /** 进度条起始X坐标*/ private float startX; /** 进度条起始Y坐标*/ private float startY; /** 进度条当前X坐标*/ private float dx; /** 进度条当前Y坐标*/ private float dy; /**进度条背景画笔*/ private Paint seekBackgroundPaint; /**进度条进度画笔*/ private Paint seekProgressPaint; /**文字画笔*/ private Paint textPaint; /**文字背景画笔*/ private Paint textBackgroundPaint; /**进度点画笔*/ private Paint seekPaint; /** 进度调整指数*/ private float adjustmentFactor = getTextSizeDip(50); /**进度背景图层*/ private RectF rectBg = new RectF(); /**进度条图层*/ private RectF rectProgress = new RectF(); /**进度点图层*/ private RectF rectSeek = new RectF(); /** 底部距离*/ private int bottom = 8; /** 左边距离*/ private int left = 8; /** 右边距离*/ private int right = 8; /** 顶部距离*/ private int top = 8; /**进度条长度*/ private int seekbarLength; /**进度条进度*/ private float progress = 0f; /**进度点宽度*/ private float seekWidth = getTextSizeDip(4); /**进度点高度*/ private float seekHeight = getTextSizeDip(14); /**进度条上方文字*/ private String progressText="01-03 10:22:02"; /**文字距离*/ private float textHeight = getTextSizeDip(20); /**文字背景宽度*/ private float bgWidth = getTextSizeDip(110); /**文字背景高度*/ private float bgHeight = getTextSizeDip(24); /**测试文本的规格*/ private Paint.FontMetrics fm; /** 是否手指按下的标志位 */ private boolean isPressed = false; /**进度监听*/ private onChangeListener listener; public MyHorizontalSeekBar(Context context) { super(context); } public MyHorizontalSeekBar(Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.context = context; init(); } public MyHorizontalSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; init(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = getWidth(); height = getHeight(); startX = getPaddingLeft() + left; startY = height - bottom - barWidth/2; dx = startX + seekbarLength * progress/100f; dy = startY; seekbarLength = width - getPaddingRight() - getPaddingLeft() - left - right; rectBg.set(startX,height - bottom - barWidth,width-right-getPaddingRight(),height - bottom); } private void init(){ seekBackgroundPaint = new Paint(); seekBackgroundPaint.setAntiAlias(true); seekBackgroundPaint.setStrokeWidth(1); seekBackgroundPaint.setColor(Color.parseColor("#d2d7d7")); seekBackgroundPaint.setStyle(Paint.Style.FILL); seekProgressPaint = new Paint(); seekProgressPaint.setAntiAlias(true); seekProgressPaint.setStrokeWidth(1); seekProgressPaint.setColor(Color.parseColor("#00bf8f")); seekProgressPaint.setStyle(Paint.Style.FILL); textBackgroundPaint = new Paint(); textBackgroundPaint.setAntiAlias(true); textBackgroundPaint.setStrokeWidth(1); textBackgroundPaint.setColor(Color.parseColor("#d2d7d7")); textBackgroundPaint.setStyle(Paint.Style.FILL); textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setStrokeWidth(1); textPaint.setTextSize(getTextSizeDip(12)); textPaint.setColor(Color.parseColor("#4d5e58")); seekPaint = new Paint(); seekPaint.setAntiAlias(true); seekPaint.setStrokeWidth(1); seekPaint.setColor(Color.parseColor("#00bf8f")); seekPaint.setStyle(Paint.Style.FILL); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制背景 canvas.drawRoundRect(rectBg,4,4,seekBackgroundPaint); //绘制进度 drawSeekProgress(canvas); //绘制进度点 drawSeekMark(canvas); //绘制文字及文字背景 if(isPressed){//需要按下才显示 // drawTextBackground(canvas); } drawTextBackground(canvas); } /** * 绘制进度条 */ private void drawSeekProgress(Canvas canvas){ rectProgress.set(startX,height - bottom - barWidth,startX + seekbarLength * progress/100f,height - bottom); canvas.drawRoundRect(rectProgress,4,4,seekProgressPaint); } /** * 绘制进度点 * @param canvas */ private void drawSeekMark(Canvas canvas){ dx = startX + seekbarLength * progress/100f; rectSeek.set(dx - seekWidth/2f,dy - seekHeight/2f,dx + seekWidth/2f, dy + seekHeight/2f); canvas.drawRect(rectSeek,seekPaint); } /** * 设置文字和文字背景区域 */ private void drawTextBackground(Canvas canvas){ fm = textPaint.getFontMetrics(); float left = dx - bgWidth/2; left = left < startX ? startX : left;//超出左边距 float right = left + bgWidth; right = right > (startX + seekbarLength) ? (startX + seekbarLength) : right;//超出右边距 left = right - bgWidth; float top = dy - textHeight - bgHeight - barWidth/2; float bottom = dy - textHeight - barWidth/2; canvas.drawRect(left,top,right,bottom,textBackgroundPaint); float textWidth = textPaint.measureText(progressText); float textY = bottom - bgHeight/2 - fm.descent/2 - fm.ascent/2; float textX = dx - textWidth/2; float textLeftX = startX + bgWidth/2 - textWidth/2; float textRight = startX + seekbarLength - bgWidth/2 - textWidth/2; textX = textX < textLeftX ? textLeftX : textX; textX = textX > textRight ? textRight : textX; canvas.drawText(progressText, textX,textY,textPaint); } /** * 重写onTouch方法 */ @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); boolean up = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: moved(x, y, up); break; case MotionEvent.ACTION_MOVE: moved(x, y, up); break; case MotionEvent.ACTION_UP: up = true; moved(x, y, up); break; } return true; } private void moved(float x, float y, boolean up){ float distanceX = Math.abs(x - dx); float distanceY = Math.abs(y - dy); if(distanceX < adjustmentFactor && distanceY <adjustmentFactor && !up){ isPressed = true; dx = x; dx = dx < startX ? startX : dx; dx = dx > startX + seekbarLength ? startX + seekbarLength : dx; float val = (dx - startX) * 10000/seekbarLength; progress = ((int)val)/100f; if(listener != null) listener.onChange(progress); invalidate(); }else{ isPressed = false; invalidate(); } } private float getTextSizePX(float value){ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, value, getResources().getDisplayMetrics()); } private float getTextSizeDip(float value){ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics()); } public interface onChangeListener{ public void onChange(float progress); } public void setListener(onChangeListener listener) { this.listener = listener; } public float getProgress() { return progress; } public void setProgress(float progress) { this.progress = progress; invalidate(); } public String getProgressText() { return progressText; } public void setProgressText(String progressText) { this.progressText = progressText; invalidate(); } }