欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义view实现滑动解锁效果

程序员文章站 2022-04-01 08:09:14
本文实例为大家分享了android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下1. 需求如下:近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。2. 需求效果图如下3. 实现...

本文实例为大家分享了android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下

1. 需求如下:

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

2. 需求效果图如下

Android自定义view实现滑动解锁效果

3. 实现效果展示

Android自定义view实现滑动解锁效果

4. 自定义view如下

/**
 * desc 自定义滑动解锁view
 * author zy
 * mail sunnyfor98@gmail.com
 * date 2021/5/17 11:52
 */
@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传进来

5. 调用方式如下

/**
 * desc 自定义滑动解锁view
 * author zy
 * mail sunnyfor98@gmail.com
 * date 2021/5/28 17:48
 */
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专做工具类,大概就这样。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。