1. 程式人生 > >《View的事件體系》(一)View基礎知識

《View的事件體系》(一)View基礎知識

雖然說View不是Android四大元件,但他的作用和重要性並不次於四大元件。那到底什麼才是View?View在Android中是所有控制元件的基類,不管簡單的Button還是複雜的ListView,他們共同的基類都是View。另外要提到的一點是ViewGroup同樣繼承了View,翻譯過來大概就是控制元件組,實際也是這樣,ViewGroup內部包含了一組View,他的子View同樣可以是ViewGroup。既然ViewGroup繼承了View,所以View既可以是單個控制元件也可以是由多個控制元件組成的一組控制元件,通過這種結構就形成了View樹。舉個例子,Button是一個View,那LinearLayout不僅是一個View還是一個ViewGroup。有了更深入的學習之後就可以定義自定義View,比如繼承自View或者ViewGroup的控制元件。

先介紹一些View的基礎知識,便於以後更深入的學習。View有很多基礎概念,比較主要的有View的位置引數、MotionEvent、TouchSlop、VelocityTracker、GestureDetector和Scroll物件。下面會逐一介紹。

(1)View的位置引數

View的位置主要由View的四個屬性決定,分別是top、left、right和bottom。其中前兩者對應左上角的縱座標和橫座標,後兩者對應右下角的橫座標和縱座標。強調一點,這四個座標是相對於他的父容器而言的,並不是在螢幕的絕對座標。下面是View和父容器座標的關係圖:

         

解釋一下,在Android中原點在螢幕的左上角,向右和向下分別是X軸和Y軸的正方向。好像大部分顯示系統都是用這個標準定義座標系的。圖中ViewGroup是View的父容器。從而View的寬高很容易的減法就計算出來了。但是在Android3.0之後,View增加了四個引數: x , y, translationX和tranlationY。

這個時候注意了,實際開發中可能需要View有平移的功能,此時top和left儲存的是View未平移時原始左上角座標,在平移的過程中View的左上角相對於父容器將會產生偏移值,這兩個方向上的偏移值就儲存在translationX和tranlationY。x和y是平移後View左上角相對父容器的座標值。那麼很顯然:

x  = left + tranlationX;

y  = top+tranlationY;

所以平移後發生改變的是Android3.0新增的四個引數,前面說的四個引數不變。

(2)MotionEvent和TouchSlop

MotionEvent對應了手指觸控式螢幕幕後所產生的一系列事件,典型的有以下幾種:

·ACTION-DOWN:手指剛接觸螢幕

·ACTION-MOVE:手指在螢幕上移動

·ACTION-UP:手指從螢幕上鬆開的一瞬間

通過MotionEvent物件我們可以獲得點選事件發生的座標值:

·getX/getY:返回相對於當前View左上角的x和y;

·getRawX/getRawY:返回相對於手機螢幕左上角的x和y。


TouchSlop是系統所能識別出的被認為是滑動的最小距離,如果手指在平面上滑動的起點和終點的距離小於這個值則不認為是滑動。這是一個和系統有關的常量,不同裝置的這個值可能是不同的。所以使用者在螢幕上滑動一會再鬆開可能觸發一系列MotionEvent:DOWN->MOVE->……MOVE->UP。在我們處理滑動的時候,可以通過設定這個常量的做一些滑動的過濾,比如小於幾倍的TouchSlop就不認為是滑動,提高使用者體驗。

(3)VelocityTracker

這個引數代表速度追蹤,用於追蹤手指在介面的滑動速度,包括水平和數直兩個方向的速度。使用很簡單,首先在View的onTouchEvent方法追蹤當前點選事件的速度:

VelocityTracker velocityTracker = VelocityTracker.obtain();

velocityTracker.addMovement();

接著通過下面的方式獲取速度:

velocityTracker.computeCurrentVelocity(1000);

int xVelocity =(int) velocityTracker.getXVelocity();

int yVelocity =(int) velocityTracker.getYVelocity();

程式碼中可以看出需要先呼叫computeCurrentVelocity計算出速度,方法引數的預設單位是ms,這裡使用1000指1s內手指在縱橫兩個方向劃過的畫素作為速度。注意這裡的速度是有方向的,向螢幕負方向滑動速度就是負值,向正方向滑動速度就是正值。最後不需要他的時候記得用clear方法重置並回收記憶體:

velocityTracker.clear();

velocityTracker.recycle();

可見這個引數掌握起來並不複雜

(4) GestureDetector

GestureDetector代表手勢識別,用於輔助檢測使用者的單擊、滑動、長按和雙擊等行為,他的使用也不復雜。參考下面的過程:

首先建立他的物件:

GestureDetector gestureDetector = new GestureDetector();

gestureDetector.setIsLongpressEnabled(false);//解決長按螢幕沒有響應的現象

接著接管View的onTouchEvent方法,在監聽View的onTouchEvent方法中新增:

boolean consume =gestureDetector.onTouchEvent();

return consume;

下面就可以看需要實現onGestureListener和onDoubleTapListener等GestureDetector的其他介面,不再詳述。實際開發中也沒必要一定用GestureDetector,在View的onTouchEvent方法完全可以實現監聽。不過如果僅僅監聽滑動,在View的onTouchEvent方法實現即可;如果監聽雙擊,用GestureDetector比較好。

(5)Scroll

Scroll指彈性滑動物件,用於實現View的彈性滑動。開發的時候使用ScrollTo和ScrollBy完成的過程是瞬間的,沒有過渡效果,所以體驗並不好。這個時候就可以用Scroll實現有過渡效果的滑動。但是僅僅它本身並不能完成,還需要和View的computeScroll相互配合才行。下面是一個典型程式碼:

Scroller scroller =new Scroller(context);

private voidsmoothScrollTo(int x,int y){

   int scrollX = getScrollX();

   int delta = x – scrollX;

   //1000秒內滑向x,慢慢移動

   scroller.startScroll(scrollX,0,delate,0,1000);

   invalidate();

}

@Override

public voidcomputeScroll(){

   if(scroller.computeScrollOffset()){

     scrollTo(scroller.getCurrX(),scroller.getCurrY());

      postInvalidate();

}

}