无码人妻精一区二区三区,eeuss影院www在线观看,无码精品久久久久久人妻中字,日韩av高清在线看片

推薦新聞
Android GestureDetector 手勢識別器的使用
發(fā)布者:深藍互聯(lián)
發(fā)布時間:2019-08-06
點擊:次

學(xué)習自定義View,這個對于初學(xué)者來說確實有點難度。因為這需要你熟悉View繪制的基本流程,不僅如此,你還需要熟悉手勢識別、解決事件沖突等知識。這是一系列綜合性的學(xué)習,如果想在Android方面進階,你必須攻克這個首要技能。今天,我們的目的是學(xué)習自定義ViewGroup實現(xiàn)ViewPager類似的滑動效果。

先來看一下我們要實現(xiàn)的效果,其實這個和原生ViewPager效果一樣的。

  • 效果圖

此篇是為了學(xué)習自定義View為目的文章,因為處于初學(xué)階段,我們先從簡單的實現(xiàn)效果一步步進階。自定義ViewGroup必須重寫父類的一個方法onLayout(),我們來看一下這個方法的介紹。

大意:這個方法用于對子視圖進行布局,分配子視圖大小和位置。ViewGroup必須重寫這個方法,根據(jù)子視圖的左上、右下角的坐標來確定其大小和位置。

代碼及實現(xiàn)

那么,讓我們繼承ViewGroup來實現(xiàn)這樣效果。先看一下我們的MyViewPager類,它簡單的對子視圖進行了布局。

/**
 * @Created by xww.
 * @Creation time 2018/8/13.
 */
 
public class MyViewPager extends ViewGroup {
 
    private GestureDetector mGestureDetector;
 
    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }
 
            @Override
            public void onShowPress(MotionEvent e) {
 
            }
 
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }
 
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                scrollBy((int) distanceX, getScrollY());
                return true;
            }
 
            @Override
            public void onLongPress(MotionEvent e) {
 
            }
 
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                return false;
            }
        });
    }
 
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            //對于每個子View進行布局
            View childView = getChildAt(i);
            childView.layout(i * getWidth(), t, (i + 1) * getWidth(), b);
        }
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        return true;
    }
}

對于每個子視圖(圖片)進行了全屏幕的占用,我們看onLayout()方法里的代碼,先獲取了每個子視圖,對子視圖進行大小和位子的設(shè)置。這里我們依照ViewPager,將子視圖橫向排成一排,每一張圖片占一整個屏幕。下面是我們添加圖片的代碼,不予解釋了。

    private int[] imgs = {R.drawable.bg_01, R.drawable.bg_02, R.drawable.bg_03, R.drawable.bg_04, R.drawable.bg_05, R.drawable.bg_06};
 
    private void initViewPager() {
        for (int img : imgs) {
            AppCompatImageView imageView = new AppCompatImageView(getContext());
            imageView.setBackgroundResource(img);
            myViewpager.addView(imageView);
        }
    }

這里我用到了GestureDetector類,這個類指明是手勢識別器,它內(nèi)部封裝了一些常用的手勢操作的接口,比如單機、雙擊、長按、滾動等。因為我們用到滾動手勢,所以我們在這里中斷(處理)它的事件。對于scrollTo、scrollBy、Scroller有疑問的可以看我之前的一篇文章:理解scrollTo、scrollBy、Scroller的一些區(qū)別及用法,掌握視圖滾動方式以及屏幕坐標系

根據(jù)手指滑動產(chǎn)生的distanceX,我們進行子視圖的滾動,并且在onTouchEvent中處理我們的手勢識別器的事件。到了這一步,我們變可以看到它的滑動效果。

優(yōu)化代碼

是不是和我們預(yù)想的不太一樣?動是可以動了,但它不會自己動,還會卡在中間,是不是感覺很不爽。那這樣子的話,我們就得借助另一個滾動視圖的類Scroller類。同理,這個類的用法在上面一個快捷鏈接中也有說明,這里我就不講它是如何使用了。我們看看最終修改后的MyViewPager類。

/**
 * @Created by xww.
 * @Creation time 2018/8/13.
 */
 
public class MyViewPager extends ViewGroup {
 
    private GestureDetector mGestureDetector;
    private int currentIndex;
    private int startX;
    private int endX;
    private Scroller mScroller;
 
    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
        mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }
 
            @Override
            public void onShowPress(MotionEvent e) {
 
            }
 
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }
 
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                scrollBy((int) distanceX, getScrollY());
                return true;
            }
 
            @Override
            public void onLongPress(MotionEvent e) {
 
            }
 
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                return false;
            }
        });
    }
 
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            //對于每個子View進行布局
            View childView = getChildAt(i);
            childView.layout(i * getWidth(), t, (i + 1) * getWidth(), b);
        }
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = (int) event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                endX = (int) event.getX();
 
                int tempIndex = currentIndex;
                if (startX - endX > getWidth() / 2) {    //從右往左滑動
                    tempIndex++;
                } else if (endX - startX > getWidth() / 2) {    //從左往右滑動
                    tempIndex--;
                }
                scrollIndex(tempIndex);
                break;
        }
        return true;
    }
 
    /**
     * 移動到指定頁面
     */
    private void scrollIndex(int tempIndex) {
        //第一頁,無法繼續(xù)向左滑動
        if (tempIndex < 0) {
            tempIndex = 0;
        }
        //同理,最后一頁無法向右滑動
        if (tempIndex > getChildCount() - 1) {
            tempIndex = getChildCount() - 1;
        }
        currentIndex = tempIndex;
        mScroller.startScroll(getScrollX(), 0, currentIndex * getWidth() - getScrollX(), 0);
        postInvalidate();
    }
 
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), 0);
            postInvalidate();
        }
    }
}

它實現(xiàn)的思路:我們給予每張圖片一個下標,當我們將當前頁面滾動的距離大于屏幕寬度的一半時,子視圖將自動滾動到下一張圖;同理,當前頁面滾動的距離小于屏幕寬度的一半,那將自動恢復(fù)原始狀態(tài),不會滾動到下一張圖。主要是在onTouchEvent()方法中,標記起始點和滑動后的最終點的坐標距離,用滑動距離比對屏幕的一半寬度,然后在處理是否要切換圖片。代碼實現(xiàn)不是很難,多于理解它實現(xiàn)的原理,相信你很快就會掌握自定義View。

 

關(guān)注深藍互聯(lián)公眾號
Copyright ? 2013-2025 深藍互聯(lián) 版權(quán)所有
友情鏈接: