Android自定义view实现滑动解锁效果
程序员文章站
2022-06-23 08:57:42
本文实例为大家分享了android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下1. 需求如下:近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。2. 需求效果图如下3. 实现...
本文实例为大家分享了android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下
1. 需求如下:
近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。
2. 需求效果图如下
3. 实现效果展示
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专做工具类,大概就这样。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。