本篇文章记录如何实现一个简单炫酷的滑动条Slider
效果:
主要知识点
- 自定义View,离不开的绘制工具画板和一些其它属性
- 如何实现滑动过程不越界
- 如何实现滑动比值的回调
- 如何封装,方便以后随时使用
首先创建一个Slider类继承View
class Slider : View {}
然后是绘制工具画板和一些其它属性
//画笔
private val mPaint: Paint by lazy {
Paint().apply {
color = mColor!!
strokeWidth = mLineWidth
style = Paint.Style.STROKE
}
}
//颜色
private var mColor: Int? = null
//线宽
private var mLineWidth: Float = dp2px(context,3)
//小圆半径
private var mRadius:Float? = null
//记录线条变化值
private var position = 0f
//绘制不可变的线条背景
private val mSliderPaint: Paint by lazy {
Paint().apply {
color = Color.BLACK
strokeWidth = mLineWidth
style = Paint.Style.STROKE
}
}
//绘制小圆
private val mCirclePaint: Paint by lazy {
Paint().apply {
color = mColor!!
style = Paint.Style.FILL
}
}
如何实现滑动过程不越界
答:在触摸事件里,控制可触摸点的范围
position = when {
position < -1 -> {
0f
}
position > measuredHeight - mRadius + 1 -> {
measuredHeight - mRadius
}
else -> {
event.y
}
}
如何实现滑动比值的回调
答:通过定义的接口OnSliderChangedListener里的sliderCallBack方法回调给用户触摸值
/**
* 接口,实现滑动条触摸值回调
* */
public interface OnSliderChangedListener{
fun sliderCallBack(p:Float)
}
/**
* 监听器
* */
private var listener:OnSliderChangedListener? = null
/**
* 注册监听器
* */
public fun addListener(listener: OnSliderChangedListener){
this.listener = listener
}
/**
* 回调方法
* */
private fun callSliderValueBack(){
listener?.sliderCallBack(position)
}
然后在触摸事件里调用回调方法
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
position = when {
position < -1 -> {
0f
}
position > measuredHeight - mRadius + 1 -> {
measuredHeight - mRadius
}
else -> {
event.y
}
}
callSliderValueBack()
invalidate()//刷新
}
MotionEvent.ACTION_MOVE -> {
position = when {
position < - 1 -> {
0f
}
position >= measuredHeight - mRadius + 1 -> {
measuredHeight - mRadius
}
else -> {
event.y
}
}
callSliderValueBack()
invalidate()//刷新
}
MotionEvent.ACTION_UP -> {
//松手
}
}
return true
}
具体绘制控件
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawLine(measuredWidth / 2f,0f,measuredWidth / 2f,measuredHeight * 1f,mSliderPaint)
canvas?.drawCircle(measuredWidth / 2f,position + mRadius!!,mRadius!!,mCirclePaint)
canvas?.drawLine(measuredWidth / 2f,0f,measuredWidth / 2f,position.toFloat(),mPaint)
}
如何封装,方便以后随时使用
- 首先在
values
这个目录下新建一个attrs
的xml文件
- 然后自定义相关属性在
attrs
文件中
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Slider">
<attr name="mColor" format="color|integer"/>
<attr name="mRadius" format="float|integer|dimension"/>
</declare-styleable>
</resources>
- 最后回调
Slider
类中提取属性
private fun initAttr(context: Context, attrs: AttributeSet) {
val array = context.obtainStyledAttributes(attrs,R.styleable.Slider)
mColor = array.getColor(R.styleable.Slider_mColor, Color.BLACK)
mRadius = array.getFloat(R.styleable.Slider_mRadius,dp2px(context,6))
array.recycle()
}