1. 程式人生 > >Android中實現滑動的七種方法

Android中實現滑動的七種方法

在Android中想要實現實現滑動有很多方法,這篇部落格將提供一些實現滑動的思路,希望可以幫助到有需要的人。

一、Android座標體系

在講解滑動之前,我們有必要簡單提一下Android的座標體系,因為滑動的實質就是座標的不斷改變,所以我們先來了解一下Android座標系檢視座標系兩個概念。直接放上兩張圖片吧,一目瞭然。

Android座標系

檢視座標系

從上面的兩張圖可以看出,Android座標系的座標原點位於螢幕的左上角,而檢視座標系的原點位於父檢視的左上角,既然提供了兩種不同的座標系,那麼我們如何來獲取座標呢,Android已經給我們提供了一些方法用於獲取這些座標,看下面的圖便一目瞭然。

Android獲取座標的各種方法

二、layout方法

在View進行繪製時,是呼叫onLayout()方法來確定View的位置的,同樣我們也可以呼叫layout()方法來傳入我們滑動後的座標便可以實現View的滑動,當然座標的獲取我們可以在觸控事件中進行獲取,下面我們做一個View隨手指進行滑動的小例子來進行說明。

public class DragView extends View {
    private int mLastX;
    private int mLastY;
    public DragView(Context context) {
        this(context, null
); } public DragView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { int
x = (int) event.getX(); int y = (int) event.getY(); int lastX = 0, lastY = 0; switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY); break; } return true; } }

上面我們在觸控事件中獲取到獲取到手指按下時的座標(lastX, lastY),然後在手指移動時不斷計算X和Y方向上的偏移量,然後再呼叫layout()方法來改變View的位置從而實現滑動。當然上面我們是通過getX()getY()來獲取檢視座標來進行修改,我們也可以通過getRawX()getRawY()來獲取絕對座標來實現上面的效果。程式碼如下:

private int mLastX;
private int mLastY;
@Override
public boolean onTouchEvent(MotionEvent event) {
    int x = (int) event.getRawX();
    int y = (int) event.getRawY();
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            mLastX = x;
            mLastY = y;
            break;
        case MotionEvent.ACTION_MOVE:
            int offsetX = x - mLastX;
            int offsetY = y - mLastY;
            layout(getLeft() + offsetX, getTop() + offsetY,
                    getRight() + offsetX, getBottom() + offsetY);
            //重新設定初始座標
            mLastX = x;
            mLastY = y;
            break;
    }
    return true;
}

上面一定要注意,我們在改變完View的位置後必須呼叫設定初始座標,這樣才能準確獲取偏移量。

三、offsetLeftAndRightoffsetTopAndBottom

這一種方法和上一種方法大部分步驟都是相同的,只是在移動View上有所差別,程式碼如下:

offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);

上面的這種方法只是多了一層封裝,可以實現比上面實現同樣的效果。

四、設定LayoutParams

LayoutParams可以通過改變的佈局引數,我們可以通過下面的程式碼實現上面同樣的效果。

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

注意:我們的LayoutParams可以通過getLayoutParams()方法來獲取,但是要注意,如果View的父佈局是LinearLayout,那麼我們的LayoutParams就是LinearLayout.LayoutParams,如果View的父佈局是RelativeLayout,則我們的LayoutParams就是RelativeLayout.LayoutParams。當然我們還有一種簡單的方法,不用再管父佈局的佈局方式。程式碼如下:

ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
marginLayoutParams.leftMargin = getLeft() + offsetX;
marginLayoutParams.topMargin = getTop() + offsetY;
setLayoutParams(marginLayoutParams);

上面的這種方法不用管父佈局的型別,使用起來更加方便。

五、scrollToscrollBy方法

關於這兩個方法我們需要仔細說一下其中的一些注意事項

1 . scrollTo的引數是具體的一個座標點(x, y), 而scrollBy的引數是在x, y方向上的座標偏移

2 . scrollToscrollBy移動的是View的內容。這一點很重要!!!!

如果我們對ViewGroup使用scrollToscrollBy則移動的是內部的所有子View, 如果對TextView使用scrollToscrollBy則移動的是其中額文字。

3 . 檢視移動還有一個不太好理解的地方在於座標,我們下面結合圖片來說明一下:

檢視移動1

檢視移動2

我們可以這樣理解,我們的手機螢幕作為一個蓋板,在手機螢幕下面是一個巨大的畫布,我們的手機螢幕這個蓋板是透明的,導致只有和手機螢幕重合的畫布部分才會被我們看到,我們呼叫scrollToscrollBy也可以理解為是在移動手機上面的蓋板。如圖中所示,按鈕在ViewGroup中的座標是(20, 10),當我們呼叫scrollBy(20, 10)之後,就相當於移動了螢幕上的蓋板,然後我們看到的按鈕就到了ViewGroup的左上角。這樣如果我們想讓按鈕在水平和豎直方向上各移動2010個單位,我們就必須呼叫scrollBy(-20, -10)

經過了上面的知識準備,我們這裡也使用scrollBy來實現前面實現的那個View隨手指移動的小例子:

((View)getParent()).scrollBy(-offsetX, -offsetY);

六、使用Scroller

Scroller也是滑動中很重要的一個角色,進過前面的scrollToscrollBy大家也會發現,它們的移動時瞬間完成的,滑動顯得十分突兀,Google為了改善使用者體驗,便給出了Scroller,它可以實現平滑的移動,從而使滑動過程更加真實,使用者體驗更好,下面我們先簡單說說Scroller的實現原理。

Scroller的實現方式類似於scrollToscrollByscrollToscrollBy的移動都是從一個座標點瞬間移動到另一個左邊點,而Scroller則是將移動的這段距離切分成好幾段的微小的位移,然後每一段呼叫scrollTo來不斷移動這些微小的位移,由於人眼的視覺暫留效果,就會給人平滑移動的視覺效果。

下面我們在上一步的基礎上增加一個小功能,第一部分還是View隨手指移動,但是當我們鬆開手指時,讓View自己平滑移動到最初始的位置(螢幕左上角),下面我們就來一步步介紹Scroller的用法

1 . 宣告Scroller變數,並在構造方法中進行初始化

2 . 在觸控事件的ACTION_UP(手指擡起)事件中傳入開始滑動的座標和需要滑動的距離並觸發Scroller的滑動事件

3 . 重寫computeScroll(),實現真正的滑動

下面是完整的程式碼示例:

public class DragView extends View {
    private int mLastX;
    private int mLastY;
    //宣告Scroller變數
    private Scroller mScroller;
    public DragView(Context context) {
        this(context, null);
    }

    public DragView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //在構造方法中初始化Scroller變數
        mScroller = new Scroller(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getRawX();
        int y = (int) event.getRawY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                //實現View跟隨手指移動的效果
                ((View)getParent()).scrollBy(-offsetX, -offsetY);
                //重新設定初始座標
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                //當手指擡起時執行滑動過程
                View view = (View) getParent();
                mScroller.startScroll(view.getScrollX(), view.getScrollY(),
                        view.getScrollX(), view.getScrollY(), 5000);
                //呼叫重繪來間接呼叫computeScroll()方法
                invalidate();
                break;
        }
        return true;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        //判斷滑動過程是否完成
        if (mScroller.computeScrollOffset()){
            ((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //通過重繪來不斷呼叫computeScroll()方法
            invalidate();
        }
    }
}

上面的程式碼View隨手指移動的程式碼部分是與前面相同的,我們只說說Scroller的部分以及一些注意事項

1 . startScroll()方法各引數的意義,我們可以看看下面的原始碼:

/**
 * Start scrolling by providing a starting point, the distance to travel,
 * and the duration of the scroll.
 *
 * @param startX Starting horizontal scroll offset in pixels. Positive
 *        numbers will scroll the content to the left.
 * @param startY Starting vertical scroll offset in pixels. Positive numbers
 *        will scroll the content up.
 * @param dx Horizontal distance to travel. Positive numbers will scroll the
 *        content to the left.
 * @param dy Vertical distance to travel. Positive numbers will scroll the
 *        content up.
 * @param duration Duration of the scroll in milliseconds.
 */
public void startScroll(int startX, int startY, int dx, int dy, int duration)

可以看出startXstartY引數就是開始滾動的(x, y)座標,那麼我們就可以通過ViewGroup(子View的父檢視)getScrollX()getScrollY()來獲取,這裡一定要注意,我們在滑動時的content就是子View,所以我們通過子View的父檢視(ViewGroup)的getScrollX()getScrollY()獲取到的就是子View在X和Y方向上滑動的距離,即就是我們需要的當我們手指擡起時子View的(x, y)座標。而如果我們對子View呼叫getScrollX()getScrollY()方法,則獲得的是子View內部的檢視的滑動距離及座標。

dxdy分別是在X和Y方向上的偏移量,而且註釋中說了,如果我們傳入的dxdy的值是正值,那麼將會向上向左移動這個content(其實就是我們這裡的View),即我們就可以讓子View回到左上角,這裡我們還是可以藉助於上一小節中提到的檢視移動的概念,我們想讓子View向坐上方移動,其實就是想讓覆蓋在上面的蓋板向右下角移動,我們可以將dxdy理解為父檢視(覆蓋在上面的蓋板)的偏移量。

假設我們剛開始是讓子View隨手指向右下方移動,那麼相當於覆蓋在上面的蓋板是向左上方移動,所以我們通過getScrollX()getScrollY()獲得的值是負值,我們現在鬆開手指想讓子View向左上方移動(即回到螢幕左上角),那麼就相當於蓋板向右下角移動,所以我們的dxdy的值必須是-getScrollX()-getScrollY(),此時的兩個值都是正值。

2 . 由於我們的computeScroll()方法不會主動呼叫,但是我們又需要它不斷呼叫從而不斷進行微小移動從而實現平滑的滑動,所以我們可以通過下面的方法。

這三個按照以下順序進行呼叫 invalidate()—>onDraw()—>computeScroll(),所以我們可以可以在ACTION_UP中呼叫完startScroll()方法後呼叫invalidate()方法,然後在computeScroll()方法中判斷滑動是否結束,如果沒結束,則通過getCurrX()getCurrY()來獲得當前需要移動的微小的位移的座標點,然後傳入scrollTo()方法中,這時候子View還只是移動了一小段距離,然後我們再次呼叫invalidate()方法,然後接著呼叫onDraw()方法,然後再次進入computeScroll()中再次讓子View移動一小段距離,直到滑動結束,computeScrollOffset()返回false,則這個迴圈呼叫的過程結束,從而完成平滑移動的過程。

七、屬性動畫

屬性動畫一樣可以實現View的滑動,但是由於屬性動畫涉及到的知識點也是眾多,這裡不再展開來寫,只是提供一個思路,後續後專門寫一篇部落格來說。

八、ViewDragHelper

ViewDragHelper可以幫助我們實現各種滑動需求,但是它的使用也相對較複雜,所以準備專門寫一篇部落格來介紹他,這裡只是給出一個概念

相關推薦

Android實現滑動方法

在Android中想要實現實現滑動有很多方法,這篇部落格將提供一些實現滑動的思路,希望可以幫助到有需要的人。 一、Android座標體系 在講解滑動之前,我們有必要簡單提一下Android的座標體系,因為滑動的實質就是座標的不斷改變,所以我

記錄Android實現滑動的幾方法

一、layou方法 程式碼示例如下,自定義一個view,在onTouchEvent()方法中計算手指滑動時的偏移量,呼叫view的layout()方法,在當前left、top、right、bottom上加上偏移量,實現view的滑動。 public clas

Android按鈕實現的兩方法

剛接觸Android開發,第一篇部落格,也就當做筆記吧, 這裡先說一個問題,在很多Android開發書中可能是版本太早的問題,都說res/layout下有一個main.xml檔案中放著排版資訊,但是個人在實際中見到的是res/menu下是main.xml中只有少量其他資訊,

實現滑動方法(Android群英傳)

內容是博主照著書敲出來的,博主碼字挺辛苦的,轉載請註明出處,後序內容陸續會碼出。   當了解了Android座標系和觸控事件後,我們再來看看如何使用系統提供的API來實現動態地修改一個View的座標,即實現滑動效果。而不管採用哪一種方式,其實現的思想基本是一致

Android實現滑動方法實踐

  在講解滑動之前,要先熟悉一下安卓的座標系。安卓檢視有兩個座標系,一個是Android座標系,一個是檢視座標系。前者以螢幕的最左上角為原點,向右為X軸正方向,向下為Y軸正方向。後者以父檢視的左上角為原點,其它與前者一致。   而獲取座標的方法也可以分為兩類,View提供的

Android實現滑動方法

1.layout方法 每次移動後,呼叫layout()方法對自己重新佈局從而達到移動的效果 @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) e

Android 實現 View 滑動方法

記錄下系統提供的 View 滑動的 API 方法。不管採用哪一種方式,本質的思想基本上都是一致的,當觸控 View 的時候,記錄下當前觸控點的座標,當手指移動的時候,記錄移動後的觸控點座標,從而獲取相對上一次座標點的偏移量,通過偏移量來修改 View 的座標,這

Android實現滑動方法總結

在android開發中,滑動對一個app來說,是非常重要的,流暢的滑動操作,能夠給使用者帶來用好的體驗,那麼本次就來講講android中實現滑動有哪些方式。其實滑動一個View,本質上是移動一個View,改變其當前所屬的位置,要實現View的滑動,就必須監聽使用者觸

Android Scroll分析 (二) 教你使用方法實現滑動

實現滑動的基本思想是:當觸控View時,系統記下當前觸控點座標;當手指移動時,系統記下移動後的觸控點座標,從而獲取到相對於前一次座標點的偏移量,並通過偏移量來修改View的座標,這樣不斷重複,從而實現滑動過程. 2.1 Layout方法 在View進行繪

Android實現延時執行操作的幾方法

在Android開發中我們可能會有延時執行某個操作的需求,例如我們啟動應用的時候,一開始呈現的是一個引導頁面,過了兩三秒後,會自動跳轉到主介面。這就是一個延時操作。  下面是實現延時執行操作的幾種方法: 1.使用執行緒的休眠實現延時操作    new Thread() {

【字串反轉總結】Java方法實現

演算法比較簡單,註釋就能說明問題,直接上程式碼! 方法一:(利用遞迴實現) public static String reverse1(String s) { int length = s.length(); if (length <= 1) retur

基於Android實現定時器的3解決方法

在Android開發中,定時器一般有以下3種實現方法:一、採用Handler與執行緒的sleep(long)方法 二、採用Handler的postDelayed(Runnable, long)方法 三、採用Handler與timer及TimerTask結合的方法下面逐一介紹

實現滑動方法

週末,android群英傳與Android開發藝術探索兩本書到了,確實是適合android進階的好書, 以後書中學到的覺得不錯的內容會寫在這個模組。 今天介紹滑動的七種方式 基本思想: 當手指按下時,記下當前座標 lastX, last

AndroidView滑動實現方式

必須 elf 內部 track 視圖 相對 top roc mar 滑動作為Android中最基礎的特效之一,使用場景非常廣泛。實現的方式也有多種,理解各種滑動的實現方式。清楚在開發中根據自己的實際需求,選擇合理的實現方案。這篇文章從:scrollTo()/scroll

Android實現震動的方法

實現手機震動其實很簡單,手機震動使用是Vibrator類,然後震動也是需要許可權的,在使用之前在AndroidManifest.xml檔案中新增 <uses-permission android:name="android.permission.VIBRATE"/>

css實現兩欄佈局,左側固定寬,右側自適應的方法

一個面試會問的問題,如何實現兩個盒子,左側固定寬度,右側自適應。 下面是實現的其中方法: 1、利用 calc 計算寬度的方法 css程式碼如下: .box{overflow: hidden;height: 100px;margin: 10px 0;} .box&

Android實現「類方法指令抽取方式」加固方案原理解析

一、前言Android中加固方案一直在進步,因為新的加固方案出來就會被人無情的破解脫殼了,從第一代加固方案落地加密dex檔案,第二代加固方案不落地加密dex檔案,在到第三代加固方案類方法抽取,以後後面的

Oraclespool命令實現的兩方法比較

要輸出符合要求格式的資料檔案只需在select時用字元連線來規範格式。比如有如下表 SQL>; select id,username,password from myuser;//測試表1 John       12342 Jack       123453 Rose       23454

方法實現Python抓取資料的視覺化

  Python 的scientific stack(一個介紹Python科學計算包的網站)已經完全成熟,並且有各種各樣用例的庫,包括機器學習(連結:machine learning),資料分析(連結:data analysis)。資料視覺化是探索資料和清晰的解釋結果很重要的一部分,

AndroidListView的幾常見的優化方法

Android中的ListView應該算是佈局中幾種最常用的元件之一了,使用也十分方便,下面將介紹ListView幾種比較常見的優化方法: 首先我們給出一個沒有任何優化的Listview的Adapter類,我們這裡都繼承自BaseAdapter,這裡我們使用一個包含10