1. 程式人生 > >自定義View--你要掌握的基本知識

自定義View--你要掌握的基本知識

View的基礎知識

注1:本文內容純作者手打原創,如需轉載請註明出處。

注2:作者目前在找工作,初級安卓工程師的水平如有需要的請留言或私信,萬分感謝。

開篇

作為android中承擔視覺化功能的控制元件,雖然View不是四大元件,不過它的作用有時候可比四大元件更重要,android官方給我盟提供了很多的基礎控制元件,不過很多時候這些控制元件無法滿足歐文們的需求,因此,我們需要根據現有的需求,結合基礎控制元件來自定義View實現我們想要的功能,不過在自定義View之前,先要對View的基礎知識有一定的瞭解才可以。在此特別感謝徐宜生先生的書,對於View方面的知識講的十分到位,獲益匪淺,特此感謝,(怎麼感覺我不是在寫部落格,像是在買書啊?)

引數基礎

在自定義View的時候通常都會需要獲得View的當前座標啊,移動距離啊等,對於View的獲得當前引數的方式有很多,先看下圖,之後在一一說明。

圖片來自徐宜生先生的書《Android群英傳》

通過上圖我們可以清楚明瞭的知道對於view的各種get方法所獲得的值所代表的含義,中間的圓點指的是事件的觸控點。上圖中的方法我就不解釋了,說幾個圖中沒有的。

從Android3.0開始View增加了幾個額外的引數:x,y,translationX,translationY,其中x,y是指View的左上角座標,translationX與translationY是指View的左上角相對於父容器的偏移量,這幾個引數也都是相對於父容器,並且translationX與translationY預設是0。

x=left+translationX;

y=top+translationY;

需要關注的是在View的平移過程中或者滑動過程中(分具體的滑動實現),top和left是指原始的左上角位置資訊,其值不會發生改變,而x,y,translationX,translationY發生改變。

事件託管

MotionEvent,可以參考我之前寫的部落格android中事件分發機制 ,這裡就不多說了。

TouchSlop在之前的文章中出現過,在這裡簡單的介紹一下,TouchSlop是系統能夠識別出的被認為是滑動的最小距離,就是說,當手指在螢幕上滑動的時候,如果兩次滑動的距離小於這個常量值,系統就不認為你在進行滑動操作。通常我們可以用一下程式碼來獲得這個引數

 ViewConfiguration.get(getApplicationContext()).getScaledTouchSlop();

其中需要一個Context物件。

事件處理幫助類:
VelocityTracker 速度追蹤者,用於追蹤手指在滑動過程中的速度,包括水平方向和豎直放量兩種,使用方式:

 @Override
public boolean onTouchEvent(MotionEvent event) {
    //建立物件
    VelocityTracker velocityTracker=VelocityTracker.obtain();
    //新增事件
    velocityTracker.addMovement(event);
    //設定計算時間
    velocityTracker.computeCurrentVelocity(1000);
    //獲得軸向速度
    int xVelocity= (int) velocityTracker.getXVelocity();
    int yVelocity= (int) velocityTracker.getYVelocity();
    //重置並回收
    velocityTracker.clear();
    velocityTracker.recycle();
}

需要注意的有兩點,一是在獲得速度之前要先呼叫設定計算時間的方法,二是速度的計算是終止位置減去起始位置之後再除以時間,所以速度可以為負值。最後記得清一下,回收。

GestureDetector 手勢處理者。用於輔助檢測使用者的單擊,滑動,長按,雙擊等行為。使用方式也不復雜,主要就是明白和熟悉對應的介面就可以。

public boolean onTouchEvent(MotionEvent event) {
    GestureDetector gestureDetector=new GestureDetector(this, new GestureDetector.OnGestureListener() {
        //手指觸控式螢幕幕的一瞬間,由一個ACTION_DOWN觸發
        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }
        //手指觸控式螢幕幕,尚未鬆開或拖動。
        @Override
        public void onShowPress(MotionEvent e) {
        }
        //手指(輕輕觸控式螢幕幕後)鬆開,伴隨著一個ACTION_UP事件
        //單擊行為
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
        //手指按下並拖動,由一個ACTION_DOEN和多個ACTION_MOVE觸發,
        //拖動行為
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }
        //使用者長久地按住螢幕不放,長按行為
        @Override
        public void onLongPress(MotionEvent e) {
        }
        //使用者按下螢幕,快速滑動鬆開,由一個DOWN,多個MOVE,一個UP事件觸發
        //快速滑動行為
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    });
    gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
        //嚴格意義上的單擊行為,在執行了此方法之後不可能在跟著一個單擊行為
        //就是隻可能是單擊行為,不可能是雙擊中的一次單擊行為。
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            return false;
        }
        //雙擊,由兩次連續的點選組成,不能與onSingleTapConfirmed共存
        //注意可能會出現重複執行onSingleTapUp單擊事件的情況。(猜測)
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            return false;
        }
        //表示發生了雙擊行為,在雙擊的期間都會觸發此方法
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            return false;
        }
    });
    gestureDetector.setContextClickListener(new GestureDetector.OnContextClickListener() {
        //在上下文在被點選的時候呼叫(API23)
        @Override
        public boolean onContextClick(MotionEvent e) {
            return false;
        }
    });
    boolean consume=gestureDetector.onTouchEvent(event);
    return consume;

程式碼中已經把每個方法的回撥時機和所代表的行為都進行了註釋,應該都能看懂,一共有三個介面我們可以去實現,不過通常情況下不會需要這麼多,而且對於這麼多介面和方法,我們在使用的時候也不方便,所有android中已經幫我能寫好了一個實現類SimpleOnGestureListener,這個類實現了上面的三個介面,在使用的時候重寫裡面的方法就可以了。這樣關於手勢處理者的介紹就結束了。

ViewDragHelper拖動手勢處理者,用於處理View的拖拽檢測和處理。在我之前的部落格有詳細的說明,可以移步到ViewDragHelper的原始碼分析,裡面有詳細的說明。

Scroller 彈性滑動物件,用於實現View的彈性滑動。這個類的使用網上有很多,大家可以自行參考。

通過以上的介紹,對於View中事件的處理大家應該有了一定的認識,在實際的開發中可以根據需要來使用不同的幫助類來實現想要的效果,但是也不要忘了這些輔助的本質都是對MotionEvent中事件的處理,有時候可以不用輔助類,直接在onTouchEvent方法中就行判斷。

滑動解決方案

對於View的滑動解決方案有很多種,以下是《群英傳》中介紹的七種方法。

  1. layout方法:改變onLayout(Layout)佈局時的引數。
  2. offsetLeftAndRight與offsetTopAndBottom :對左右,上下移動的APi的封裝,效果跟layout方法一樣。
  3. LayoutParams:LayoutParams儲存了一個View的佈局引數,可以動態的改變佈局引數中的某一個屬性,並重新設定給View,實現View的滑動。注意在獲取這個引數的時候要根據父容器的型別還獲得不同的LayoutParams。推薦使用ViewGroup.MarginLayoutParams來實現。
  4. scrollTo與scrollBy方法:移動的是View的內容而不是Vi額外本身,scrollTo表示移動到指定位置,scrollBy表示相對於現在的位置移動到指定位置。注意是瞬間執行。
  5. Scroller:具有過渡效果的移動,這是與scrollTo,scrollBy的最大的區別。
  6. 動畫:可以使用屬性動畫,補間動畫,幀動畫,來實現View的滑動。優缺點應該都清楚。最新的方式還可以使用Material Design的方式來實現(對這個目前瞭解的不多,就不多說了)。
  7. ViewDragHelper:推薦大家使用的一個幫助類,可以參考之前我寫的部落格。

對於這七中方法,可以根據實際情況來選擇,當個使用或組合使用多可以,當然還有一些其他的方法也能實現滑動,也不更多介紹了(其實我也不知道還有什麼。重寫onDraw?),學會這七種在處理滑動的時候就夠用了。

總結

對於自定義View來說,View的引數獲取,輔助的幫助類,滑動的解決方案,是我們應該瞭解的。這篇文章對自定義View的基礎知識進行了一些總結,希望可以幫助大家。文中有不對的地方,請不吝賜教。

同樣在最後說一句,在找工作。。。