✏️ 丨 自定义滑动解锁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专做工具类,大概就酱紫。

更多相关文章

  1. Android————一个简单记账本(Bookkeeping)
  2. Android实现左右滑动效果
  3. Android处理ListView的条目长按事件
  4. Android开源DiscreteSeekbar:动画气泡指示当前滑动值
  5. Android之——JNI配置C语言打印Logcat信息
  6. Android(安卓)*#06#显示的更改
  7. AndroidHttpClient使用Cookie应用分析
  8. Android(安卓)Container原理分析
  9. 两分钟彻底让你明白Android中onInterceptTouchEvent与onTouchEve

随机推荐

  1. How to get the android resolution
  2. 【Android】常见异常 —— android.view.
  3. android:layout_weight android:weightSu
  4. Android:自定义toast
  5. Android开发者网址导航
  6. android转屏处理
  7. android 复制字符串到剪贴板
  8. Android版本检测\自动更新
  9. android 页面切换动画效果
  10. android hardware 简述(Android系统源码情