Android自定義view實現滑動解鎖效果
本文實例為大傢分享瞭Android自定義view實現滑動解鎖的具體代碼,供大傢參考,具體內容如下
1. 需求如下:
近期需要做一個類似屏幕滑動解鎖的功能,右劃開始,左劃暫停。
2. 需求效果圖如下
3. 實現效果展示
4. 自定義view如下
/** * Desc 自定義滑動解鎖View * Author ZY * Mail [email protected] * 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 [email protected] * 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專做工具類,大概就這樣。
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Android自定義view仿QQ的Tab按鈕動畫效果(示例代碼)
- Android中SurfaceView和普通view的區別及使用
- Android自定義View實現星星評分效果
- Android自定義控件實現通用驗證碼輸入框(二)
- Android自定義View實現圓弧進度的效果