一、View的位置参数
1、left、bottom、right、top
(1)left: mLetft = getLeft() View的左上角横坐标
(2)right:mRight = getRight() View的右下角横坐标
(3)top: mTop = getTop() View的左上角纵坐标
(4)bottom: mBottom = getBottom View的右下角纵坐标
这些坐标是相对于View的父容器而言的,是一个相对坐标。
2、x,y
View左上角的坐标,是View在窗口的实际位置。
3、translationX,transactionY
View左上角相对于父容器的偏移量,默认为0。
且有x = left + translationX
View在平移的过程中,top和left是原始左上角的位置信息,其值不会发生改变,此时发生改变的是x、y、translationX,translationY。
二、MotionEvent和TouchSlop
1、MotionEvent
MotionEvent提供了获取事件发生时x和y坐标的获取方法。
getX()/getY() 返回相对于当前View左上角的x和y坐标。
getRawX()/getRawY() 返回相对于手机屏幕左上角的x和y坐标。
2、TouchSlop
系统能识别出的被认为是滑动的最小距离。该值是常量,跟设备有关,不同设备可能是不同的值,该值可用来过滤一些两次滑动事件的距离过小的场景。
获取方式:
ViewConfiguration.get(applicationContext).scaledTouchSlop
三、VelocityTracker、GestureDetector和Scroller
1、VelocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括水平速度和竖直速度。
class TempLinearLayout(context: Context) : LinearLayout(context) {
private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
override fun onTouchEvent(event: MotionEvent?): Boolean {
velocityTracker.addMovement(event)
when(event?.action) {
MotionEvent.ACTION_MOVE -> {
velocityTracker.computeCurrentVelocity(100) //计算当前速度,指一短时间内手指划过的像素数,传入的值单位ms
val xVelocity = velocityTracker.xVelocity //速度值是矢量值,带方向,如果从右往左滑速度为负值
val yVelocity = velocityTracker.yVelocity
}
MotionEvent.ACTION_UP -> {
velocityTracker.clear()
velocityTracker.recycle() //TODO 如果不再使用则recycler
}
}
return super.onTouchEvent(event)
}
}
速度 = (终点位置 - 起点位置) / 时间段
2、GestureDetector
手势检测,用于辅助监测用户的单击、滑动、长按、双击等行为。
class TempLinearLayout(context: Context) : LinearLayout(context) {
private val gestureDetector = GestureDetector(context, object : GestureDetector.OnGestureListener {
override fun onShowPress(e: MotionEvent?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onSingleTapUp(e: MotionEvent?): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDown(e: MotionEvent?): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent?,
velocityX: Float,
velocityY: Float
): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float
): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onLongPress(e: MotionEvent?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
override fun onTouchEvent(event: MotionEvent?): Boolean {
return gestureDetector.onTouchEvent(event) //接管View的onTouchEvent
}
}
3、Scroller
用于实现View的弹性滑动,可以实现有过渡效果的滑动,其过程不是瞬间完成的,而是在一定的时间间隔内完成,需要与View的computeScroll方法配合使用。
class TempLinearLayout(context: Context) : LinearLayout(context) {
private val scroller: Scroller = Scroller(context)
fun smoothScrollTo(destX: Int, destY: Int) {
val scrollX = scrollX
val delta = destX - scrollX
scroller.startScroll(scrollX, 0, delta, 0, 1000) //duration 单位ms
invalidate()
}
override fun computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.currX, scroller.currY)
postInvalidate()
}
}
}
4、scrollBy和scrollTo
/**
* Set the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the x position to scroll to
* @param y the y position to scroll to
*/
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
/**
* Move the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the amount of pixels to scroll by horizontally
* @param y the amount of pixels to scroll by vertically
*/
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
在滑动过程中,mScrollX的值总等于View左边缘和View内容左边缘在水平方向的距离,mScrollY总等于View上边缘和View内容上边缘在竖直方向的距离。
结尾
摘抄自《Android开发艺术探索》