Android自定義view實現(xiàn)滑動解鎖效果
本文實例為大家分享了Android自定義view實現(xiàn)滑動解鎖的具體代碼,供大家參考,具體內(nèi)容如下
1. 需求如下:
近期需要做一個類似屏幕滑動解鎖的功能,右劃開始,左劃暫停。
2. 需求效果圖如下

3. 實現(xiàn)效果展示

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. 調(diào)用方式如下
/**
* 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框架,集工具類、自定義組件、網(wǎng)絡(luò)請求框架一體,感覺用起來有些厚重,接下來會抽時間做拆分,ZyFrame保留網(wǎng)絡(luò)請求功能,ZyUI專做自定義組件,ZyTool專做工具類,大概就這樣。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中如何優(yōu)雅的處理重復(fù)點擊實例代碼
這篇文章主要給大家介紹了關(guān)于Android中如何優(yōu)雅的處理重復(fù)點擊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
Kotlin StateFlow單數(shù)據(jù)更新熱流設(shè)計與使用介紹
StateFlow當(dāng)值發(fā)生變化,就會將值發(fā)送出去,下流就可以接收到新值。在某些場景下,StateFlow比LiveData更適用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09
Android自定義recyclerView實現(xiàn)時光軸效果
這篇文章主要介紹了Android自定義recyclerView實現(xiàn)時光軸效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01
Android Service中使用Toast無法正常顯示問題的解決方法
這篇文章主要介紹了Android Service中使用Toast無法正常顯示問題的解決方法,分析了Service中Toast無法正常顯示的原因與相關(guān)的解決方法,具有一定參考借鑒價值,需要的朋友可以參考下2016-10-10
Android Broadcast原理分析之registerReceiver詳解
這篇文章主要介紹了Android Broadcast原理分析之registerReceiver詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
Android開發(fā)手冊Chip監(jiān)聽及ChipGroup監(jiān)聽
這篇文章主要為大家介紹了Android開發(fā)手冊Chip監(jiān)聽及ChipGroup監(jiān)聽,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06

