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>
完成