android 自定义View中滑动操作防止超出边界的简便方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 自定义View中滑动操作防止超出边界的简便方法相关的知识,希望对你有一定的参考价值。
参考技术A 在android开发中,自定义View中经常会用到滑动操作,肯定要防止滑动超出边界。这里是一个防止滑出边界非常简便的一个方法。计算左右边界X或上下边界Y的值,如果不超出屏幕,左边边界与顶部边界是0,右边与底部边界是屏幕宽高度。然后重写scrollTo方法:
@Overridepublic void scrollTo(int x, int y)
if(x>mRightOffsetX) x=mRightOffsetX;
if(x<mLeftOffsetX) x=mLeftOffsetX;
super.scrollTo(x, y);
Android 自定义滑动解锁View
✏️ 丨 自定义滑动解锁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专做工具类,大概就酱紫。
以上是关于android 自定义View中滑动操作防止超出边界的简便方法的主要内容,如果未能解决你的问题,请参考以下文章