
效果圖
分析
結(jié)構(gòu)拆分
- 灰色背景:圓角矩形
- 白色進(jìn)度條:圓角矩形
- 進(jìn)度條按鈕:圖片
- 提示文字
注意
- 快速滑動(dòng)時(shí)X軸返回值超過(guò)最大可滑動(dòng)距離要做處理
@SuppressLint("ResourceAsColor")
class CustomSlideButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
/**
* 自定義屬性相關(guān)
*/
private var thumbImg by Delegates.notNull<Int>()
private var bgColor by Delegates.notNull<Int>()
private var pgColor by Delegates.notNull<Int>()
private var thumbColor by Delegates.notNull<Int>()
private var centerTextColor by Delegates.notNull<Int>()
private var centerTextSize by Delegates.notNull<Int>()
private var centerText:String
private var thumbRadius by Delegates.notNull<Int>()
/**
* 畫筆
*/
private val paintBg:Paint by lazy { Paint() }
private val paintPg:Paint by lazy { Paint() }
private val paintCenterText:Paint by lazy { Paint() }
private lateinit var ovalFull:RectF
private lateinit var ovalProgress:RectF
private var downX:Float=0f //按下位置x
private var downY:Float=0f //按下位置y
private var progressRight=0 //內(nèi)圈右邊距離
private var progressBarPadding=0 //內(nèi)圈padding
private var thumbBitmap: Bitmap //thump 圖片
private var finishSlide=false //完成滑動(dòng)
private var followMode=false //左邊跟隨滑動(dòng)
private var moveX=0f //當(dāng)前移動(dòng)距離
private var maxMoveX=0 //最大移動(dòng)距離
private var viewWidth:Int=0 //width
private var viewHeight:Int=0 //height
private var anmitonReset:ValueAnimator?=null //重置view動(dòng)畫
interface SlideFinishListener {
fun finishSlide()
}
private var slideFinishListener: SlideFinishListener? = null
fun setSlideFinishListener(slideFinishListener: SlideFinishListener?) {
this.slideFinishListener = slideFinishListener
}
init {
val typeArray =
context.theme.obtainStyledAttributes(attrs, R.styleable.CustomSlideBarStyle, defStyleAttr, 0)
thumbImg=
typeArray.getResourceId(R.styleable.CustomSlideBarStyle_thumbImg,R.mipmap.ic_open_net)
bgColor = typeArray.getColor(R.styleable.CustomSlideBarStyle_backgroundFull, R.color.white_70)
pgColor =
typeArray.getColor(R.styleable.CustomSlideBarStyle_progressColor, R.color.white)
thumbColor =
typeArray.getColor(R.styleable.CustomSlideBarStyle_thumbColor, R.color.white)
centerTextColor=
typeArray.getColor(R.styleable.CustomSlideBarStyle_centerTextColor,R.color.black)
centerTextSize=
typeArray.getDimensionPixelSize(R.styleable.CustomSlideBarStyle_centerTextSize,27)
centerText=
typeArray.getString(R.styleable.CustomSlideBarStyle_centerText).toString()
followMode=
typeArray.getBoolean(R.styleable.CustomSlideBarStyle_leftFollowRight,true)
typeArray.recycle()
progressBarPadding=context.resources.getDimensionPixelSize(R.dimen.silide_bar_padding)
thumbBitmap=BitmapFactory.decodeResource(context.resources,thumbImg)
paintBg.color = bgColor
paintBg.alpha= (255*0.7).toInt()
paintCenterText.style=Paint.Style.FILL
paintBg.isAntiAlias=true
paintPg.color=pgColor
paintPg.style=Paint.Style.FILL
paintPg.isAntiAlias=true
paintCenterText.color=centerTextColor
paintCenterText.style=Paint.Style.FILL
paintCenterText.textSize= centerTextSize.toFloat()
paintCenterText.textAlign = Paint.Align.CENTER
paintCenterText.isFakeBoldText=true //粗體
paintCenterText.isAntiAlias=true
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//畫背景
ovalFull= RectF(if(followMode)moveX else 0f,0f, viewWidth.toFloat(), viewHeight.toFloat())
canvas.drawRoundRect(ovalFull,thumbRadius.toFloat(),thumbRadius.toFloat(),paintBg)
//畫文字
drawCenterText(canvas)
//畫進(jìn)度條
ovalProgress= RectF(if(followMode) progressBarPadding.toFloat()+ moveX else progressBarPadding.toFloat(),progressBarPadding.toFloat(), progressRight.toFloat()+moveX, viewHeight.toFloat()-progressBarPadding.toFloat())
canvas.drawRoundRect(ovalProgress,thumbRadius.toFloat(),thumbRadius.toFloat(),paintPg)
//畫進(jìn)度按鈕
canvas.drawBitmap(thumbBitmap,progressBarPadding.toFloat()+moveX,progressBarPadding.toFloat(),null)
}
/**
* 畫中間文字
*/
private fun drawCenterText(canvas: Canvas) {
if (followMode && moveX!=0f){//跟隨滑動(dòng)模式下,滑動(dòng)到最左邊才顯示中間文字
return
}
//畫文字
//計(jì)算baseline
val fontMetrics: FontMetrics = paintCenterText.fontMetrics
val distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom
val baseline: Float = ovalFull.centerY() + distance
// canvas.drawText(centerText, ovalFull.centerX(), baseline, paintCenterText)
canvas.drawText(
centerText,
viewHeight + (viewWidth - viewHeight) / 2f,
baseline,
paintCenterText
)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
thumbRadius=h/2
viewWidth=w
viewHeight=h
progressRight=h-progressBarPadding
maxMoveX=w-h
//壓縮圖片到指定大小
thumbBitmap= BitmapUtil.zoomImg2(thumbBitmap,h-progressBarPadding*2,h-progressBarPadding*2)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when(event.action){
MotionEvent.ACTION_DOWN->{
//按下位置在按鈕范圍內(nèi)才接收
if (event.x in 0f..viewHeight.toFloat() && event.y in 0f..viewHeight.toFloat()){
downX= event.x
downY= event.y
}
}
MotionEvent.ACTION_MOVE->{
if (downX!=0f && downY!=0f){
var currMovex=event.x-downX
if (currMovex<0){currMovex=0f}
if (currMovex.toInt() in 0..maxMoveX){
moveX=currMovex
invalidate()
}else if(currMovex.toInt()>=maxMoveX){
if (!finishSlide){
moveX= maxMoveX.toFloat() //快速滑動(dòng)超出最大可移動(dòng)范圍時(shí),直接繪制到最右端
invalidate()
finishSlide=true
slideFinishListener?.finishSlide()
}
}
}
}
MotionEvent.ACTION_UP->{
if (downX!=0f && downY!=0f && !finishSlide){
downX=0f
downY=0f
if (moveX!=0f){
resetSlideButton()//未完成滑動(dòng),重置view
}
}
}
}
return true
}
private fun resetSlideButton(){
if (anmitonReset?.isRunning == true){
return
}
anmitonReset = ValueAnimator.ofFloat(moveX,0f)
anmitonReset!!.duration = 200
anmitonReset!!.interpolator= AccelerateInterpolator()
anmitonReset!!.addUpdateListener { animation ->
moveX = animation.animatedValue as Float
invalidate()
}
anmitonReset!!.start()
}
public fun resetState(){
if (anmitonReset?.isRunning == true){
anmitonReset?.cancel()
}
finishSlide=false
downY=0f
downX=0f
resetSlideButton()
}
}
attrs.xml
<declare-styleable name="CustomSlideBarStyle">
<attr name="thumbImg" format="reference"/>
<attr name="thumbColor" format="color"/>
<attr name="backgroundFull" format="color"/>
<attr name="progressColor" format="color"/>
<attr name="centerText" format="string"/>
<attr name="centerTextColor" format="color"/>
<attr name="centerTextSize" format="dimension"/>
<attr name="leftFollowRight" format="boolean"/>
</declare-styleable>