Android自定义水平拖动条(SetpSeekBar)
如图所示:拖动进度条,松开时离哪个刻度进,就自动滑到临近的刻度位置

1、自定义属性 res->values下创建attrs.xml文件
<declare-styleable name="EasySeekBar">
<attr name="configuration" format="string"/>
<attr name="progress_bg_color" format="color"/>
<attr name="progress_color" format="color"/>
<attr name="circle_r" format="dimension"/>
<attr name="line" format="dimension"/>
<attr name="circle_color" format="color"/>
<attr name="max_progress" format="integer"/>
<attr name="min_progress" format="integer"/>
<attr name="progress_with" format="integer"/>
</declare-styleable>
2、自定义View
package com.example.customseekbar.easy;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.example.customseekbar.R;
public class StepSeekBar extends View {
private Context context;
private String TAG = "StepSeekBar";
private Paint bgPaint;//seekbar背景
private Paint progressPaint;//进度
private Paint circlePaint;//控制小球
private Point centrePoint;//中心坐标
private Point WHPoint; //条形的长宽
private float progress = 0; //进度
private int value ;//值
private int space = 20;//刻度线与进度条的距离
private Paint linePaint;//竖线
private int lineColor = Color.parseColor("#DFB578"); //DFB578 D81B60
private String configuration = "horizontal";//形状 vertical、horizontal、circle、semicircle
private int bgColor;//背景颜色
private int progressColor;//进度颜色
private int circleR;//控制小球半径
private int line;//规格
private int maxProgress;//最大值
private int minProgress;//最小值
private int circleColor;//小球颜色
private int strokeWidth;
private boolean isTure;
private EasySeekBarLister easySeekBarLister;
public StepSeekBar(Context context) {
super(context);
this.context = context;
init(null);
}
public void setEasySeekBarLister(EasySeekBarLister easySeekBarLister) {
this.easySeekBarLister = easySeekBarLister;
}
public StepSeekBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
init(attrs);
}
public StepSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(attrs);
}
private void init(AttributeSet attrs) {
initAttrs(attrs);
initPaint();
}
private void initAttrs(AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.EasySeekBar);
try {
configuration = typedArray.getString(R.styleable.EasySeekBar_configuration);
bgColor = typedArray.getColor(R.styleable.EasySeekBar_progress_bg_color, Color.parseColor("#999999"));
progressColor = typedArray.getColor(R.styleable.EasySeekBar_progress_color,Color.parseColor("#ffffff"));
circleR = typedArray.getDimensionPixelOffset(R.styleable.EasySeekBar_circle_r,40);
line = typedArray.getDimensionPixelOffset(R.styleable.EasySeekBar_line,400);
maxProgress = typedArray.getInt(R.styleable.EasySeekBar_max_progress,100);
minProgress = typedArray.getInt(R.styleable.EasySeekBar_min_progress,0);
circleColor = typedArray.getColor(R.styleable.EasySeekBar_circle_color,Color.parseColor("#ffffff"));
strokeWidth = typedArray.getInt(R.styleable.EasySeekBar_progress_with,12);
}finally {
typedArray.recycle();
}
centrePoint = new Point();
WHPoint = new Point();
if (circleR<strokeWidth/2){
centrePoint.x = line+strokeWidth/2;
centrePoint.y = line+strokeWidth/2;
WHPoint.x = line+strokeWidth;
WHPoint.y = strokeWidth;
}else {
centrePoint.x = line+circleR;
centrePoint.y = line+circleR;
WHPoint.x = line+2*circleR;
WHPoint.y = 2*circleR;
}
setValue(minProgress);
}
private void initPaint() {
//初始低画笔
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bgPaint.setAntiAlias(true);
bgPaint.setColor(bgColor);
bgPaint.setStrokeWidth(strokeWidth-2);
bgPaint.setStrokeCap(Paint.Cap.ROUND);
//初始进度画笔
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setAntiAlias(true);
progressPaint.setColor(progressColor);
progressPaint.setStrokeCap(Paint.Cap.ROUND);
progressPaint.setStrokeWidth(strokeWidth);
//初始小球画笔
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setAntiAlias(true);
circlePaint.setColor(circleColor);
//竖线
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setAntiAlias(true);
linePaint.setColor(lineColor);
linePaint.setStrokeWidth(5);
linePaint.setStrokeCap(Paint.Cap.ROUND);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (configuration){
case "horizontal":
canvas.drawLine(WHPoint.y/2,WHPoint.y/2+space,line+WHPoint.y/2,WHPoint.y/2+space,bgPaint);
canvas.drawLine(WHPoint.y/2,WHPoint.y/2+space,progress+WHPoint.y/2,WHPoint.y/2+space,progressPaint);
canvas.drawCircle(progress+WHPoint.y/2,WHPoint.y/2+space,circleR,circlePaint);
drawLine(canvas); //刻度线
break;
}
}
//刻度线
private void drawLine(Canvas canvas){
int k = maxProgress - minProgress;
for (int i = 0; i <= k; i++){
if (i != 0 && i != k){
float x = WHPoint.y/2 + (line/(float)k *i);
canvas.drawLine(x,2,x,10,linePaint);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (configuration){
case "horizontal":
horTouch(event);
break;
}
return true;
}
private void horTouch(MotionEvent event) {
float x = event.getX();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
// if (!isTure){
// getParent().requestDisallowInterceptTouchEvent(true);
// int point = ((int) x);
// if (point<0){
// point = 0;
// }else if (point>line){
// point = line;
// }
// progress = point;
// }
break;
case MotionEvent.ACTION_MOVE:
/*int pointX = ((int) x-circleR);
if (pointX<0){
pointX = 0;
}else if (pointX> line){
pointX = line;
}
progress = pointX;*/
int pointX = ((int) x-circleR);
if (pointX<0){
pointX = 0;
}else if (pointX> line){
pointX = line;
}
Log.i("打印进度值:","pointX = "+pointX + " ,line = "+line);
progress = pointX;
break;
case MotionEvent.ACTION_UP:
getParent().requestDisallowInterceptTouchEvent(false);
int len = maxProgress - minProgress;
float dan = line/(float)len;
float zuiXiao = line;
int u = len;
for (int i = 0; i <= len; i++){
//Log.i("打印i =",""+i);
float k = dan*i;
float jue = Math.abs(k- progress);//求绝对值
if (jue < zuiXiao){
zuiXiao = jue;
u = i;
}
}
Log.i("打印进度值zuiXiao:",""+zuiXiao);
progress = u*dan;
Log.i("打印进度值uu:",""+u +" ,progress = "+progress +" ,dan = "+dan +" ,line = "+line);
if (easySeekBarLister != null){
value = (int)getVHValue(progress);
Log.i("打印进度值111:",""+value);
easySeekBarLister.onProgress(value);
}
break;
}
invalidate();
}
/**
* @describe 绝对值
* @param i
* @return
*/
private int getAbs(int i) {
if (i<0){
i = -i;
}
return i;
}
public int getValue() {
return value;
}
public void setValue(int value) {
if (value < minProgress){
this.value = minProgress;
}else if (value > maxProgress){
this.value = maxProgress;
}else {
this.value = value;
}
progress = ValueToProgress(this.value);
invalidate();
}
private float ValueToProgress(int value) {
switch (configuration){
case "horizontal":
return progress = (value-minProgress)*line/(maxProgress - minProgress);
}
return minProgress;
}
private float getVHValue(float progress) {
return progress*(maxProgress - minProgress) / line+minProgress;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
switch (configuration){
case "horizontal":
setMeasuredDimension(WHPoint.x,WHPoint.y+space);
break;
}
}
public interface EasySeekBarLister{
void onProgress(int pro);
}
}
3、布局文件
<com.example.customseekbar.easy.StepSeekBar
android:id="@+id/stepSeekBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="350dp"
app:circle_color="#F6B363"
app:circle_r="8dp"
app:configuration="horizontal"
app:line="300dp"
app:max_progress="8"
app:min_progress="0"
app:progress_bg_color="#F7F1F7"
app:progress_color="#FFDFB8"
app:progress_with="15" />
<TextView
android:id="@+id/tv_step"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="400dp"
android:layout_centerHorizontal="true"></TextView>
4、activity
public class HorizontalActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_horizontal);
TextView tv_step = findViewById(R.id.tv_step);
StepSeekBar stepSeekBar = findViewById(R.id.stepSeekBar);
stepSeekBar.setEasySeekBarLister(new StepSeekBar.EasySeekBarLister() {
@Override
public void onProgress(int pro) {
tv_step.setText(""+pro);
}
});
stepSeekBar.setValue(7);
tv_step.setText("7");
}
}
5、color文件
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
完成
浙公网安备 33010602011771号