一、概述
这是一个带悬浮文字的水平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 = getMeasuredWidth();
height = getMeasuredHeight();
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();
}
}