3.1.2.view 的位置
view的位置主要由它的四個頂點來決定,分別對應於view的四個屬性:top、left、right、bottom,
top:左上角縱座標
left: 左上角橫座標
right:右下角橫座標
bottom:右下角縱座標
這些座標都是相對於view的父容器來說的:如圖:
通過座標很容易得出view的寬和高
width = right - left
height = bottom-top
關於view的一些屬性的獲取與含義
left = getLeft();
right = getRight();
top = getTop();
bottom = getBottom();
android 3.0後額外的屬性x,y ,translationX,translationY
x,y:是view左上角的座標
translationX,translationY:是View左上角相對於父容器的偏移量,默認值是0
注意:這幾個參數都是相對於父容器的
參數間的關係:
x = left + translationX
y = top + translationY
注意:在View平移的過程中,top, left 是view距離父控件的原始座標,是不會改變的
3.1.3 MotionEvent 和 TouchSlop
1. MotionEvent:是手指接觸屏幕後所產生的一系列事件
ACTION_DOWN — 手指剛接觸屏幕
ACTION_MOVE — 手指在屏幕上移動
ACTION_UP — 手指從屏幕上鬆開的一瞬間
通過MotionEvent 對象可以得到點擊事件過程中發生的x,y 座標
getX();getY(); : 返回的是相對於當前自身View 左上角的x,y 座標
getRawX(); getRawY(); : 返回的是相對於手機屏幕左上角的x,y座標
2.TouchSlop
TouchSlop是系統所能識別出的被認爲是滑動的最小距離,意思是:當滑動的距離小於這個常量值,那麼系統就不認爲是在進行滑動操作,這個常量和設備有關,不同設備上這個值不同
獲取方式:ViewConfiguration.get(getContext()).getScaledTouchSlop();
3.1.4 VelocityTracker GestureDetector 和 Scroller
1.VelocityTracker
速度追蹤,用於追蹤手指在滑動過程中的速度,包括水平和豎直方向的的速度
使用:在View 的onTouchEvent方法中追蹤當前點擊事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
獲取當前的速度:
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
需要注意:
- 獲取速度之前必須先計算速度,即getXVelocity 和 getYVelocity這兩個方法的前面必須使用computeCurrentVelocity()方法
- 這裏的速度是指在一段時間內手指所滑過的像素數,比如將時間間隔設爲1000ms,在1s內,手指在水平方向從左向右滑動100像素,那麼水平速度是100,如果手指由右向左滑動,那麼水平速度就爲負數
速度 = (終點位置 - 起點位置)/ 時間段
如果我們通過velocityTracker.computeCurrentVelocity(100);來獲取速度,那麼得到的速度就是手指在100ms內所滑過的像素數,因此水平速度就成了10像素/每100ms,即水平速度爲10,(這裏假設滑動過程爲勻速)
最後當不需要使用時,需要調用clear方法來重置並回收內存
velocityTracker.clear();
velocityTracker.recycle();
2.GestureDetector
手勢檢測,用於輔助檢測用戶的點擊,滑動,長按,雙擊等行爲
3.Scroller
彈性滑動對象,用於實現View的彈性滑動,當使用View的scrollTo/scrollBy方法來進行滑動時,其過程是瞬間完成的,沒有過度效果,用戶體驗不好,這個時候就可以使用Scroller來實現
Scroller scroller = new Scroller(getContext());
//緩慢滑動到指定位置
private void smoothScrollTo(int destX,int dextY){
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms內滑向destX ,效果就是緩慢滑動
mScroller.startScroll(scrollX,0,delta,0,1000);
invalidate();
}
@Override
public void computeScroll() {
if(mScroller.computeScrollOffset){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
Scroller 本身並不能實現View的滑動,他需要配合computeScroll()方法才能實現彈性滑動的效果
3.2 View 的滑動
通過三種方式可以實現View的滑動
通過View自身提供的scrollTo/scrollBy方法
通過動畫給View施加平移效果來實現滑動
通過改變View的LayoutParams使的View重新佈局從而實現滑動
3.2.1 使用scrollTo/scrollBy
View的兩個屬性mScrollX ,mScrollY ,這兩個屬性可以通過getScrollX(),getScrollY()得到,mScrollX,mScrollY的單位爲像素,是移動的距離
scrollTo/scrollBy實現view的滑動,只能將view 的內容進行移動,並不能將View本身進行滑動,
3.3 彈性滑動
三種方式實現彈性滑動
Scroller
通過動畫
使用延時策略
3.4 View的事件分發機制
3.4.1 點擊事件的傳遞規則
事件的分發過程由三個很重要的方法來共同完成dispatchTouchEvent 、onInterceptTouchEvent 、 onTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev)
用來進行事件的分發public boolean onInterceptTouchEvent(MotionEvent event)
在上述方法內部調用,用來判斷是否攔截某個事件,如果當前view攔截了某個事件,那麼在同一個事件序列當中,此方法不會被再次調用,返回結果表示是否攔截當前事件public boolean onTouchEvent(MotionEvent ev)
在dispatchTouchEvent 方法中調用,用來處理點擊事件,返回結果表示是否消耗當前事件
以上三個方法的關係用以下僞代碼表示
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consumen = onTouchEvent(ev);
}else{
consumen = child.dispatchTouchEvent(ev);
}
return consume;
}
注意:
1. viewGroup 默認是不攔截任何事件的,android源碼中viewGroup的onInterceptTouchEvent方法默認返回false
2. view沒有onInterceptTouchEvent方法,一旦有點擊事件傳遞給他,那麼它的onTouchEvent方法就會被調用
3. view的onTouchEvent默認都會消耗事件(返回true),除非它是不可點擊的(clickable 和longClickable 同時爲false).View 的longClickable屬性默認都爲false,clickable 屬性默認爲false