重读《Android 开发艺术探索》,本篇是书中的第三章内容的总结。
本章内容包括
View 基础、事件分发、滑动及了解了前面的知识如何解决滑动冲突android是什么系统问题。
更多细节见思维导图
一些代码相关的内容
获取 Tandroid/yunosouchSlop
ViewConfiguration.get(this).scaledTouchSlop
获取 VelocityTracker
// 追踪当前点击事件的速度
val velocityTracker = VelocityTracker.obtain()
velocityTracker.addMovement(event)
// 先计算
velocityTracker.computeCurrentVelocity(1000)
// 获得当前速度
val xVelocity = velocityTracker.xVelocity
val yVelocity = velocityTracker.yVelocity
...
// 不用使用,需要重置
velocityTracker.clear()
velocityTracker.recycle()
使用 GestureDetector
// 创建 GestureDetector 对象
val mGestureDetector = GestureDetector(context, object : GestureDetector.OnGestureListener {
override fun onDown(e: MotionEvent?): Boolean {
// 触摸的一瞬间
TODO("Not yet implemented")
}
override fun onShowPress(e: MotionEvent?) {
// 触摸屏幕,未松开或拖动
TODO("Not yet implemented")
}
override fun onSingleTapUp(e: MotionEvent?): Boolean {
// 松开,点击行为
TODO("Not yet implemented")
}
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float,
): Boolean {
// 手指按下并拖动,拖动行为
TODO("Not yet implemented")
}
override fun onLongPress(e: MotionEvent?) {
// 长按
TODO("Not yet implemented")
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent?,
velocityX: Float,
velocityY: Float,
): Boolean {
// 按下,快速滑动后松开,快速滑动行为
TODO("Not yet implemented")
}
})
// 设置 双击监听
mGestureDetector.setOnDoubleTapListener(object : GestureDetector.OnDoubleTapListener {
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
// 严格的单击行为,是单击而非双击中的一次点击
TODO("Not yet implemented")
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
// 双击,两次单击组成
TODO("Not yet implemented")
}
override fun onDoubleTapEvent(e: MotionEvent?): Boolean {
// 发送双击行为,会被调用多次
TODO("Not yet implemented")
}
})
// 解决长按屏幕后无法拖动的现象
mGestureDetector.setIsLongpressEnabled(false)
// 传入被监听 view 的 event
val consume = mGestureDetector.onTouchEvent(event)
使用 Scrollandroid是什么手机牌子er
// 实现弹性滑动
private val mScroller = Scroller(context)
private fun smoothScrollTo(destX: Int, destY: Int) {
val scrollX = scrollX
val delta = destX - scrollX
// 1000ms 内滑向 destX,
mScroller.startScroll(scrollX, 0, delta, 0, 1000)
invalidate()
}
override fun computeScroll() {
super.computeScroll()
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.currX, mScroller.currY)
postInvalidate()
}
}
使用外部拦截法解决滑动冲突的主要代码 只需修改父控android/yunos件
// 在父控件中添加以下代码,主要是控制是否要拦截事件,拦截添加根据实际情况添加
// 外部拦截法
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
var intercept = false
val x = event.x.toInt()
val y = event.y.toInt()
when (event.action) {
MotionEvent.ACTION_DOWN -> {
intercept = false
if (!mScroller.isFinished) {
mScroller.abortAnimation()
intercept = true
}
}
MotionEvent.ACTION_MOVE -> {
val deltaX = x - mLastXIntercept
val deltaY = y - mLastYIntercept
// 当前控件需要拦截当前事件的判断,此处的条件是:横行滑动大于垂直滑动时拦截
intercept = abs(deltaX) > abs(deltaY)
}
MotionEvent.ACTION_UP -> {
intercept = false
}
}
mLastX = x
mLastY = y
mLastXIntercept = x
mLastYIntercept = y
return intercept
}
使用内部拦截法解决滑动冲突的主要代码 父控件代android是什么系统码
// 内部拦截法
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
val x = event.x.toInt()
val y = event.y.toInt()
val action = event.action
// 不能拦截 ACTION_DOWN 事件,一旦拦截该事件那么所有事件都无法传递给子控件
if (action == MotionEvent.ACTION_DOWN) {
mLastX = x
mLastY = y
if (!mScroller.isFinished) {
mScroller.abortAnimation()
return true
}
return false
} else {
return true
}
}
子控件代码
// 内部拦截法
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
val x = event.x.toInt()
val y = event.y.toInt()
when (event.action) {
MotionEvent.ACTION_DOWN -> {
// mParentView 需要被传递给当前控件
mParentView.requestDisallowInterceptTouchEvent(true)
}
MotionEvent.ACTION_MOVE -> {
val deltaX = x - mLastX
val deltaY = y - mLastY
// 父控件需要拦截该事件的条件
if (abs(deltaX) > abs(deltaY)) {
mParentView.requestDisallowInterceptTouchEvent(false)
}
}
MotionEvent.ACTION_UP -> {
}
}
mLastX = x
mLastY = y
return super.dispatchTouchEvent(event)
}