android开发之Android 自定义滑动解锁View

自定义滑动解锁View

  1. 需求如下:

近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。

  1. 需求效果图如下
    IMG_256
  2. 实现效果展示
    IMG_257
  3. 自定义view如下

/**

*/

@SuppressLint(“ClickableViewAccessibility”)

class SlideSwitchButton : ViewGroup {

constructor(context: Context?) : this(context, null)

constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)

constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : this(

    context,

    attrs,

    defStyleAttr, 0

)

constructor(

    context: Context?,

    attrs: AttributeSet?,

    defStyleAttr: Int,

    defStyleRes: Int

) : super(context, attrs, defStyleAttr, defStyleRes)

var duration = 300

var isOpen = false

var scrollView: ScrollView? = null

var onSwitchListener: ((isOpen: Boolean) -> Unit)? = null

private var itemHeight = 0

private var itemPadding = 0

private var parentWidth = 0

private val stopImgView: ImageView by lazy {

    ImageView(context).apply {

        setImageResource(R.drawable.f1_svg_btn_stop)

    }

}

private val startImgView: ImageView by lazy {

    ImageView(context).apply {

        setImageResource(R.drawable.f1_svg_btn_start)

    }

}

private val hintView: TextView by lazy {

    TextView(context).apply {

        setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.dp_14))

        compoundDrawablePadding = resources.getDimension(R.dimen.dp_5).toInt()

        setTextColor(Color.parseColor("#727b9f"))

    }

}

init {

    setBackgroundResource(R.drawable.f1_sel_bg_slide_btn)

    addView(hintView)

    updateHint()

    addView(stopImgView)

    addView(startImgView)

    var x = 0

    startImgView.setOnTouchListener { v, event ->

        when (event.action) {

            MotionEvent.ACTION_DOWN -> {

                scrollView?.requestDisallowInterceptTouchEvent(true)

                x = event.x.toInt()

            }

            MotionEvent.ACTION_UP -> {

                if (startImgView.x < (parentWidth - startImgView.width) / 2) {

                    play(false)

                } else {

                    play(true)

                }

                scrollView?.requestDisallowInterceptTouchEvent(false)

            }

            MotionEvent.ACTION_MOVE -> {

                val lastX = event.x - x

                if (startImgView.x + lastX > parentWidth - itemPadding - startImgView.width) {

                    return@setOnTouchListener true

                }

                if (startImgView.x + lastX < itemPadding) {

                    return@setOnTouchListener true

                }

                startImgView.x += lastX

            }

        }

        return@setOnTouchListener true

    }

}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    setMeasuredDimension(widthMeasureSpec, resources.getDimension(R.dimen.dp_90).toInt())

    itemPadding = resources.getDimension(R.dimen.dp_5).toInt()

    itemHeight = resources.getDimension(R.dimen.dp_80).toInt()

    parentWidth = MeasureSpec.getSize(widthMeasureSpec)

}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {

    stopImgView.layout(

        itemPadding,

        itemPadding,

        itemPadding + itemHeight,

        itemPadding + itemHeight

    )

    startImgView.layout(

        itemPadding,

        itemPadding,

        itemPadding + itemHeight,

        itemPadding + itemHeight

    )

    val len =

        hintView.paint.measureText(hintView.text.toString()) + resources.getDimension(R.dimen.dp_24)

    val let = (r - len) / 2

    hintView.layout(

        let.toInt(),

        resources.getDimension(R.dimen.dp_35).toInt(),

        (let + len).toInt(),

        resources.getDimension(R.dimen.dp_55).toInt()

    )

}

/**

 * flag tue为开始 false为停止

 */

private fun play(flag: Boolean) {

    val mStart = startImgView.x

    val mEnd = if (flag) {

        parentWidth - itemPadding * 2 - startImgView.width.toFloat()

    } else {

        stopImgView.x - itemPadding

    }

    val animatorOBJ =

        ObjectAnimator.ofFloat(startImgView, "translationX", mStart, mEnd)

    animatorOBJ.duration = duration.toLong()

    animatorOBJ.addListener(object : Animator.AnimatorListener {

        override fun onAnimationRepeat(animation: Animator?) {

        }

        override fun onAnimationEnd(animation: Animator?) {

            updateHint(flag)

            if (flag != isOpen) {

                isOpen = flag

                onSwitchListener?.invoke(flag)

            }

        }

        override fun onAnimationCancel(animation: Animator?) {

        }

        override fun onAnimationStart(animation: Animator?) {

        }

    })

    animatorOBJ.start()

}

private fun updateHint(lock: Boolean = false) {

    val icon = if (lock) {

        hintView.text = "滑动停止"

        ResourcesCompat.getDrawable(resources, R.drawable.f1_svg_left_arrow, null)

    } else {

        hintView.text = "滑动开始"

        ResourcesCompat.getDrawable(resources, R.drawable.f1_svg_right_arrow, null)

    }

    icon?.setBounds(

        0,

        0,

        resources.getDimension(R.dimen.dp_14).toInt(),

        resources.getDimension(R.dimen.dp_12).toInt()

    )

    if (lock) {

        hintView.setCompoundDrawables(icon, null, null, null)

    } else {

        hintView.setCompoundDrawables(null, null, icon, null)

    }

}

fun stop() {

    play(false)

}

fun start() {

    play(true)

}

}

这里需要注意一点:页面过长时,ScrollView和SlideSwitchButton滑动事件会冲突,所以需要吧scrollView传进来

  1. 调用方式如下

/**

*/

class SlideSwitchButtonActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContentView(R.layout.f1_act_main)

    btn_start.scrollView = scrollView

    btn_start.onSwitchListener = {

        if (it) {

            Toast.makeText(this,"开始操作",Toast.LENGTH_LONG).show()

            btn_start.start()

        } else {

            Toast.makeText(this,"停止操作",Toast.LENGTH_LONG).show()

            btn_start.stop()

        }

    }

}

}

之前封装了一版ZyFrame框架,集工具类、自定义组件、网络请求框架一体,感觉用起来有些厚重,接下来会抽时间做拆分,ZyFrame保留网络请求功能,ZyUI专做自定义组件,ZyTool专做工具类,大概就这样。

文章来源:网络 版权归原作者所有

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系小编,我们将立即处理

猜你喜欢

转载自blog.csdn.net/xuezhangmen/article/details/132182049