真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Android觸摸事件的應(yīng)用

常見的滑動(dòng)沖突場(chǎng)景

常見的滑動(dòng)沖突場(chǎng)景可以簡(jiǎn)單分為以下三種:

十多年的市中網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整市中建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“市中網(wǎng)站設(shè)計(jì)”,“市中網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

  • 場(chǎng)景1:外部滑動(dòng)方向和內(nèi)部滑動(dòng)方向不一致

  • 場(chǎng)景2:外部滑動(dòng)方向和內(nèi)部滑動(dòng)方向一致

  • 場(chǎng)景3:上面兩種情況的嵌套

如圖:

Android觸摸事件的應(yīng)用

場(chǎng)景1,主要是將ViewPager和Fragment配合使用所組成的頁(yè)面滑動(dòng)效果,主流應(yīng)用幾乎都會(huì)使用這個(gè)效果。在這個(gè)效果中可以通過左右滑動(dòng)來切換頁(yè)面,而每個(gè)頁(yè)面內(nèi)部往往又是一個(gè)ListView,所以就造成了滑動(dòng)沖突,但是在ViewPager內(nèi)部處理了這種滑動(dòng)沖突,因此在采用ViewPager時(shí)我們就無須關(guān)注這個(gè)問題,而如果把ViewPager換成ScrollView,那就必須自己手動(dòng)處理,不然造成的結(jié)果就是內(nèi)外兩層只能一層能夠滑動(dòng)。

場(chǎng)景2,就復(fù)雜一點(diǎn),當(dāng)內(nèi)外兩層都在同一個(gè)方向可以滑動(dòng)的時(shí)候,顯然存在邏輯問題。因?yàn)楫?dāng)手指開始滑動(dòng)的時(shí)候,系統(tǒng)無法知道用戶到底是想讓哪一層滑動(dòng),所以當(dāng)手指滑動(dòng)的時(shí)候就會(huì)出現(xiàn)問題,要么只有一層滑動(dòng),要么就是內(nèi)外兩層都滑動(dòng)但很卡頓。

場(chǎng)景3,是場(chǎng)景1和場(chǎng)景2兩種情況的嵌套,顯得更復(fù)雜了。比如外部有一個(gè)SlideMenu效果,內(nèi)部有一個(gè)ViewPager,ViewPager的每一個(gè)頁(yè)面中又是一個(gè)ListView。雖然場(chǎng)景3滑動(dòng)沖突看起來很復(fù)雜,但都是幾個(gè)單一的滑動(dòng)沖突的疊加,因此需要一一拆解開來即可。

滑動(dòng)沖突的處理規(guī)則

一般來說,不管滑動(dòng)沖突有多么復(fù)雜,它都有既定的規(guī)則,根據(jù)這些規(guī)則我們就可以選擇合適的方法去處理。

對(duì)于場(chǎng)景1,它的處理規(guī)則就是:當(dāng)用戶左右滑動(dòng)時(shí),需要讓外部的View攔截點(diǎn)擊事件,當(dāng)用戶上下滑動(dòng),需要讓內(nèi)部View攔截點(diǎn)擊事件。具體來說就是根據(jù)滑動(dòng)是水平滑動(dòng)還是豎直滑動(dòng)來判斷到底是由誰(shuí)來攔截事件。

如圖:

Android觸摸事件的應(yīng)用

簡(jiǎn)單來說,就是根據(jù)水平方向和豎直方向的距離差來判斷,如果是Dx>Dy,那么則是水平滑動(dòng),如果是Dy>Dx,那么則是豎直滑動(dòng)。

場(chǎng)景2,則是比較特殊,它無法根據(jù)滑動(dòng)的角度,距離差以及速度差來做判斷。這個(gè)時(shí)候就需要從業(yè)務(wù)上找到突破點(diǎn),比如,當(dāng)處于某種狀態(tài)時(shí)需要外部View響應(yīng)用戶的滑動(dòng),而處于另外一種狀態(tài)時(shí)需要內(nèi)部View來響應(yīng)View的滑動(dòng)

對(duì)于場(chǎng)景3的話,它的滑動(dòng)規(guī)則也更復(fù)雜,和場(chǎng)景2一樣,同樣是從業(yè)務(wù)上找到突破點(diǎn)。

外部攔截法

外部攔截法是指點(diǎn)擊事件都是先經(jīng)過父容器的攔截處理,如果父容器需要此事件就攔截,如果不需要此事件,就不攔截了,這樣就可以解決滑動(dòng)沖突的問題,外部攔截法需要重寫父容器的onInterceptTouchEvent方法,在內(nèi)部做相應(yīng)的攔截即可,偽代碼如下:

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {        boolean intercepted = false;        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {
            intercepted = false;            break;
        }        case MotionEvent.ACTION_MOVE: {            if (父容器需要點(diǎn)擊當(dāng)前事件) {
                intercepted = true;
            } else {
                intercepted = false;
            }            break;
        }        case MotionEvent.ACTION_UP: {
            intercepted = false;            break;
        }        default:            break;
        }
        mLastXIntercept = x;
        mLastYIntercept = y;        return intercepted;
    }

首先ACTION_DOWN這個(gè)事件,父容器必須返回false,這樣保證后續(xù)move和up的事件可以傳遞給子View,根據(jù)move事件來決定是否攔截,如果父容器攔截就返回true,否則返回false。

實(shí)現(xiàn)一個(gè)自定義類似ViewPager的控件,嵌套ListView的效果,源代碼如下:

public class HorizontalScrollViewEx extends ViewGroup {    private static final String TAG = "HorizontalScrollViewEx";    private int mChildrenSize;    private int mChildWidth;    private int mChildIndex;    // 分別記錄上次滑動(dòng)的坐標(biāo)
    private int mLastX = 0;    private int mLastY = 0;    // 分別記錄上次滑動(dòng)的坐標(biāo)(onInterceptTouchEvent)
    private int mLastXIntercept = 0;    private int mLastYIntercept = 0;    private Scroller mScroller;                //彈性滑動(dòng)對(duì)象
    private VelocityTracker mVelocityTracker;  //追蹤滑動(dòng)速度

    public HorizontalScrollViewEx(Context context) {        super(context);        init();
    }    public HorizontalScrollViewEx(Context context, AttributeSet attrs) {        super(context, attrs);        init();
    }    public HorizontalScrollViewEx(Context context, AttributeSet attrs,            int defStyle) {        super(context, attrs, defStyle);        init();
    }    private void init() {
        mScroller = new Scroller(getContext());
        mVelocityTracker = VelocityTracker.obtain();
    }    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {        boolean intercepted = false;        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {
            intercepted = false;            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
                intercepted = true;
            }            break;
        }        case MotionEvent.ACTION_MOVE: {            int deltaX = x - mLastXIntercept;            int deltaY = y - mLastYIntercept;            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                intercepted = true;
            } else {
                intercepted = false;
            }            break;
        }        case MotionEvent.ACTION_UP: {
            intercepted = false;            break;
        }        default:            break;
        }

        Log.d(TAG, "intercepted=" + intercepted);
        mLastX = x;
        mLastY = y;
        mLastXIntercept = x;
        mLastYIntercept = y;        return intercepted;
    }    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mVelocityTracker.addMovement(event);        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }            break;
        }        case MotionEvent.ACTION_MOVE: {            int deltaX = x - mLastX;            scrollBy(-deltaX, 0);            break;
        }        case MotionEvent.ACTION_UP: {            int scrollX = getScrollX();
            mVelocityTracker.computeCurrentVelocity(1000);            float xVelocity = mVelocityTracker.getXVelocity();            if (Math.abs(xVelocity) >= 50) {
                mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;
            } else {
                mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;
            }
            mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));            int dx = mChildIndex * mChildWidth - scrollX;            smoothScrollBy(dx, 0);
            mVelocityTracker.clear();            break;
        }        default:            break;
        }

        mLastX = x;
        mLastY = y;        return true;
    }    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int measuredWidth = 0;        int measuredHeight = 0;        final int childCount = getChildCount();        measureChildren(widthMeasureSpec, heightMeasureSpec);        int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec);        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);        if (childCount == 0) {            setMeasuredDimension(0, 0);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {            final View childView = getChildAt(0);
            measuredHeight = childView.getMeasuredHeight();            setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight());
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {            final View childView = getChildAt(0);
            measuredWidth = childView.getMeasuredWidth() * childCount;            setMeasuredDimension(measuredWidth, heightSpaceSize);
        } else {            final View childView = getChildAt(0);
            measuredWidth = childView.getMeasuredWidth() * childCount;
            measuredHeight = childView.getMeasuredHeight();            setMeasuredDimension(measuredWidth, measuredHeight);
        }
    }    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int childLeft = 0;        final int childCount = getChildCount();
        mChildrenSize = childCount;        for (int i = 0; i < childCount; i++) {            final View childView = getChildAt(i);            if (childView.getVisibility() != View.GONE) {                final int childWidth = childView.getMeasuredWidth();
                mChildWidth = childWidth;
                childView.layout(childLeft, 0, childLeft + childWidth,
                        childView.getMeasuredHeight());
                childLeft += childWidth;
            }
        }
    }    private void smoothScrollBy(int dx, int dy) {
        mScroller.startScroll(getScrollX(), 0, dx, 0, 500);        invalidate();
    }    @Override
    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();
        }
    }    @Override
    protected void onDetachedFromWindow() {
        mVelocityTracker.recycle();        super.onDetachedFromWindow();
    }
}

這個(gè)情況的攔截條件就是父容器在滑動(dòng)過程中水平距離差比垂直距離差大,那么就進(jìn)行攔截,否則就不攔截,繼續(xù)傳遞事件。

內(nèi)部攔截法

內(nèi)部攔截法是指父容器不攔截任何事件,所有的事件都傳遞給子元素,如果子元素需要此事件就直接消耗掉,否則就交給父容器進(jìn)行處理,這種方法和Android中的事件分發(fā)機(jī)制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起來較外部攔截法復(fù)雜。偽代碼如下:

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {
            mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(true);            break;
        }        case MotionEvent.ACTION_MOVE: {            int deltaX = x - mLastX;            int deltaY = y - mLastY;            if (父容器需要此類點(diǎn)擊事件) {
                mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(false);
            }            break;
        }        case MotionEvent.ACTION_UP: {            break;
        }        default:            break;
        }

        mLastX = x;
        mLastY = y;        return super.dispatchTouchEvent(event);
    }

當(dāng)子元素調(diào)用requestDisallowInterceptTouchEvent(false)方法時(shí),父元素才能繼續(xù)攔截所需的事件。

前面是用自定義類似的ViewPager,現(xiàn)在重寫一個(gè)ListView,我們可以自定義一個(gè)ListView,叫做ListViewEx,然后對(duì)內(nèi)部攔截法的模板代碼進(jìn)行修改即可。

public class ListViewEx extends ListView {    private static final String TAG = "ListViewEx";    private HorizontalScrollViewEx2 mHorizontalScrollViewEx2;    // 分別記錄上次滑動(dòng)的坐標(biāo)
    private int mLastX = 0;    private int mLastY = 0;    public ListViewEx(Context context) {        super(context);
    }    public ListViewEx(Context context, AttributeSet attrs) {        super(context, attrs);
    }    public ListViewEx(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);
    }    public void setHorizontalScrollViewEx2(
            HorizontalScrollViewEx2 horizontalScrollViewEx2) {
        mHorizontalScrollViewEx2 = horizontalScrollViewEx2;
    }    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {
            mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(true);            break;
        }        case MotionEvent.ACTION_MOVE: {            int deltaX = x - mLastX;            int deltaY = y - mLastY;
            Log.d(TAG, "dx:" + deltaX + " dy:" + deltaY);            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(false);
            }            break;
        }        case MotionEvent.ACTION_UP: {            break;
        }        default:            break;
        }

        mLastX = x;
        mLastY = y;        return super.dispatchTouchEvent(event);
    }
}

同時(shí)對(duì)于包含ListViewEx外部布局進(jìn)行修改,在onInterceptTouchEvent事件上不進(jìn)行攔截

public class HorizontalScrollViewEx2 extends ViewGroup {    private static final String TAG = "HorizontalScrollViewEx2";    private int mChildrenSize;    private int mChildWidth;    private int mChildIndex;    // 分別記錄上次滑動(dòng)的坐標(biāo)
    private int mLastX = 0;    private int mLastY = 0;    // 分別記錄上次滑動(dòng)的坐標(biāo)(onInterceptTouchEvent)
    private int mLastXIntercept = 0;    private int mLastYIntercept = 0;    private Scroller mScroller;    private VelocityTracker mVelocityTracker;    public HorizontalScrollViewEx2(Context context) {        super(context);        init();
    }    public HorizontalScrollViewEx2(Context context, AttributeSet attrs) {        super(context, attrs);        init();
    }    public HorizontalScrollViewEx2(Context context, AttributeSet attrs,            int defStyle) {        super(context, attrs, defStyle);        init();
    }    private void init() {
        mScroller = new Scroller(getContext());
        mVelocityTracker = VelocityTracker.obtain();
    }    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {        int x = (int) event.getX();        int y = (int) event.getY();        int action = event.getAction();        if (action == MotionEvent.ACTION_DOWN) {
            mLastX = x;
            mLastY = y;            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();                return true;
            }            return false;
        } else {            return true;
        }
    }    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent action:" + event.getAction());
        mVelocityTracker.addMovement(event);        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }            break;
        }        case MotionEvent.ACTION_MOVE: {            int deltaX = x - mLastX;            int deltaY = y - mLastY;
            Log.d(TAG, "move, deltaX:" + deltaX + " deltaY:" + deltaY);            scrollBy(-deltaX, 0);            break;
        }        case MotionEvent.ACTION_UP: {            int scrollX = getScrollX();            int scrollToChildIndex = scrollX / mChildWidth;
            Log.d(TAG, "current index:" + scrollToChildIndex);
            mVelocityTracker.computeCurrentVelocity(1000);            float xVelocity = mVelocityTracker.getXVelocity();            if (Math.abs(xVelocity) >= 50) {
                mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;
            } else {
                mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;
            }
            mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));            int dx = mChildIndex * mChildWidth - scrollX;            smoothScrollBy(dx, 0);
            mVelocityTracker.clear();
            Log.d(TAG, "index:" + scrollToChildIndex + " dx:" + dx);            break;
        }        default:            break;
        }

        mLastX = x;
        mLastY = y;        return true;
    }    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int measuredWidth = 0;        int measuredHeight = 0;        final int childCount = getChildCount();        measureChildren(widthMeasureSpec, heightMeasureSpec);        int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec);        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);        if (childCount == 0) {            setMeasuredDimension(0, 0);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {            final View childView = getChildAt(0);
            measuredHeight = childView.getMeasuredHeight();            setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight());
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {            final View childView = getChildAt(0);
            measuredWidth = childView.getMeasuredWidth() * childCount;            setMeasuredDimension(measuredWidth, heightSpaceSize);
        } else {            final View childView = getChildAt(0);
            measuredWidth = childView.getMeasuredWidth() * childCount;
            measuredHeight = childView.getMeasuredHeight();            setMeasuredDimension(measuredWidth, measuredHeight);
        }
    }    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d(TAG, "width:" + getWidth());        int childLeft = 0;        final int childCount = getChildCount();
        mChildrenSize = childCount;        for (int i = 0; i < childCount; i++) {            final View childView = getChildAt(i);            if (childView.getVisibility() != View.GONE) {                final int childWidth = childView.getMeasuredWidth();
                mChildWidth = childWidth;
                childView.layout(childLeft, 0, childLeft + childWidth,
                        childView.getMeasuredHeight());
                childLeft += childWidth;
            }
        }
    }    private void smoothScrollBy(int dx, int dy) {
        mScroller.startScroll(getScrollX(), 0, dx, 0, 500);        invalidate();
    }    @Override
    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();
        }
    }    @Override
    protected void onDetachedFromWindow() {
        mVelocityTracker.recycle();        super.onDetachedFromWindow();
    }
}

這個(gè)攔截規(guī)則也是父容器在滑動(dòng)過程中水平距離差與垂直距離差相比。


網(wǎng)頁(yè)標(biāo)題:Android觸摸事件的應(yīng)用
URL網(wǎng)址:http://weahome.cn/article/jhjgsh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部