一酬诀、View的位置參數(shù)
1缘琅、left的猛、bottom安皱、right爷贫、top
(1)left: mLetft = getLeft() View的左上角橫坐標(biāo)
(2)right:mRight = getRight() View的右下角橫坐標(biāo)
(3)top: mTop = getTop() View的左上角縱坐標(biāo)
(4)bottom: mBottom = getBottom View的右下角縱坐標(biāo)
這些坐標(biāo)是相對于View的父容器而言的认然,是一個(gè)相對坐標(biāo)。
2漫萄、x卷员,y
View左上角的坐標(biāo),是View在窗口的實(shí)際位置腾务。
3毕骡、translationX,transactionY
View左上角相對于父容器的偏移量窑睁,默認(rèn)為0挺峡。
且有x = left + translationX
View在平移的過程中,top和left是原始左上角的位置信息担钮,其值不會發(fā)生改變橱赠,此時(shí)發(fā)生改變的是x、y箫津、translationX狭姨,translationY宰啦。
二、MotionEvent和TouchSlop
1饼拍、MotionEvent
MotionEvent提供了獲取事件發(fā)生時(shí)x和y坐標(biāo)的獲取方法赡模。
getX()/getY() 返回相對于當(dāng)前View左上角的x和y坐標(biāo)。
getRawX()/getRawY() 返回相對于手機(jī)屏幕左上角的x和y坐標(biāo)师抄。
2漓柑、TouchSlop
系統(tǒng)能識別出的被認(rèn)為是滑動(dòng)的最小距離。該值是常量叨吮,跟設(shè)備有關(guān)辆布,不同設(shè)備可能是不同的值,該值可用來過濾一些兩次滑動(dòng)事件的距離過小的場景茶鉴。
獲取方式:
ViewConfiguration.get(applicationContext).scaledTouchSlop
三锋玲、VelocityTracker、GestureDetector和Scroller
1涵叮、VelocityTracker
速度追蹤惭蹂,用于追蹤手指在滑動(dòng)過程中的速度,包括水平速度和豎直速度割粮。
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) //計(jì)算當(dāng)前速度盾碗,指一短時(shí)間內(nèi)手指劃過的像素?cái)?shù),傳入的值單位ms
val xVelocity = velocityTracker.xVelocity //速度值是矢量值穆刻,帶方向置尔,如果從右往左滑速度為負(fù)值
val yVelocity = velocityTracker.yVelocity
}
MotionEvent.ACTION_UP -> {
velocityTracker.clear()
velocityTracker.recycle() //TODO 如果不再使用則recycler
}
}
return super.onTouchEvent(event)
}
}
速度 = (終點(diǎn)位置 - 起點(diǎn)位置) / 時(shí)間段
2、GestureDetector
手勢檢測氢伟,用于輔助監(jiān)測用戶的單擊榜轿、滑動(dòng)、長按朵锣、雙擊等行為谬盐。
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
用于實(shí)現(xiàn)View的彈性滑動(dòng)诚些,可以實(shí)現(xiàn)有過渡效果的滑動(dòng)飞傀,其過程不是瞬間完成的,而是在一定的時(shí)間間隔內(nèi)完成诬烹,需要與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);
}
在滑動(dòng)過程中绞吁,mScrollX的值總等于View左邊緣和View內(nèi)容左邊緣在水平方向的距離幢痘,mScrollY總等于View上邊緣和View內(nèi)容上邊緣在豎直方向的距離。
結(jié)尾
摘抄自《Android開發(fā)藝術(shù)探索》