仿ios側滑推出當前界面

我們都知道在ios手機上面,有一個側滑退出當前界面的功能,但是在安卓手機上系統沒有給我們提供這樣的功能,但是這依然阻擋不了強大的安卓的定製功能,我們完全可以自己定製一套這樣的功能。首先看下效果圖:


分析:

(1)要想模仿ios的這種效果,因爲我們通過手指的滑動,所以這裏肯定跟我們的滑動事件有關係(onInterceptTouchEvent,onTouchEvent這兩個方法的關係,如果不清楚,請直接查閱事件傳遞機制原理)

(2)我們要想直接攔截我們的所有觸摸事件,我們可以在上層父級佈局中進行攔截和處理,這裏我們想到了DecorView。首先我們應該知道Activity的頂級父View是DecorView,獲取我們的DecorView也很簡單

getWindow().getDecorView()

我們平時寫的那些xml佈局文件都是包裹在這個DecorView中的,所以這裏我們就有了一個思路:

我們可以在我們的xml佈局和DecorView中間添加一箇中間佈局(SlidingLayout),然後所有的滑動邏輯和滑動衝突全部在這裏面處理。

(3)比較關鍵的是:當我們需要使用側滑動能的Activity我們需要將它的主題設置成透明,這樣滑動的時候就不會遮擋下面的Activity,代碼如下:

<style name="AppTheme.Slide" parent="@style/AppTheme">
        <!--Required-->
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@style/AppTheme.Slide.Animation</item>
    </style>


(4)當我們滑動超過半屏的時候,退出當前界面,否則則回退到原始位置。這裏使用Scroller


下面直接上代碼進行分析:

(1)觸摸事件的處理過程,按下的位置大於X軸的十分之一就攔截當前事件,交給SlidingLayout的onTouchEvent處理

 /**
     * 根據手指移動的距離判斷是否攔截觸摸事件
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        int x = (int) ev.getX();
        int y = (int) ev.getY();
        boolean mIntercept = false;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mInterceptDownX = x;
                mLastInterceptX = x;
                mLastInterceptY = y;
                break;
            case MotionEvent.ACTION_MOVE:

                int moveX = x - mLastInterceptX;
                int moveY = y - mLastInterceptY;
                //按下的位置的X位置小於屏幕的十分之一,並且x移動的距離大於y移動的距離,就攔截
                if (mInterceptDownX < (getWidth() / 10) && Math.abs(moveX) > Math.abs(moveY)) {
                    mIntercept = true;
                } else {
                    mIntercept = false;
                }
                mLastInterceptX = x;
                mLastInterceptY = y;

                break;
            case MotionEvent.ACTION_UP: //擡起的時候重置參數
                mIntercept = false;
                mInterceptDownX = mLastInterceptX = mLastInterceptY = 0;
                break;
        }
        return mIntercept;
    }

    private int mTouchDownX;
    private int mLastTouchX;
    private int mLastTouchY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        boolean mConsumed = false;
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mTouchDownX = x;
                mLastTouchX = x;
                mLastTouchY = y;
                break;
            case MotionEvent.ACTION_MOVE:

                int moveX = x - mLastTouchX;
                int moveY = y - mLastTouchY;
                if (mTouchDownX < (getWidth() / 10) && Math.abs(moveX) > Math.abs(moveY) && !mConsumed) {
                    mConsumed = true;
                }
                if (mConsumed) {
                    int rightMoveX = (int) (mLastTouchX - event.getX());
                    if ((getScrollX() + rightMoveX) > 0) {  //向左滑動的時候,getScrollX()和rightMoveX都大於0,所以禁止滑動
                        scrollTo(0, 0);
                    } else {
                        scrollBy(rightMoveX, 0);
                    }
                }
                mLastTouchX = x;
                mLastTouchY = y;
                break;
            case MotionEvent.ACTION_UP:

                mConsumed = false;
                mTouchDownX = mLastTouchX = mLastTouchY = 0;
                if(-getScrollX()<getWidth()/2){ //偏移量不到屏幕寬度的一般,就回到最初的位置
                    scrollBack();
                }else{
                    scrollFinish();
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                mConsumed = false;
                mTouchDownX = mLastTouchX = mLastTouchY = 0;
                if(-getScrollX()<getWidth()/2){ //偏移量不到屏幕寬度的一般,就回到最初的位置
                    scrollBack();
                }else{
                    scrollFinish();
                }
                break;
        }
        return true;
    }

(2)滑動的偏移量超出屏幕的一辦,就關閉當前界面否則回到初始位置

 /**
     * 滑動到最初的位置
     */
    private void scrollBack() {
        int startX = getScrollX();
        int dx = -getScrollX();
        mScroller.startScroll(startX, 0, dx, 0, 300);
        invalidate();
    }

    /**
     * 向右滑動關閉
     */
    private void scrollFinish(){
        int dx = -getScrollX() - getWidth();
        mScroller.startScroll(getScrollX(),0,dx,0,300);
        invalidate();
    }

(3)我們可以將這些側滑處理放在我們的BaseActivity當中,需要側滑的Activity只要繼承這個BaseActivity並且主題設置成透明就可以了

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(enableRightSliding()){

            SlidingLayout slidingLayout = new SlidingLayout(this);
            slidingLayout.replaceCurrentLayout(this);
        }

    }

    /**
     * 子類重寫這個方法true:允許向右滑動,false:禁止向右滑動
     * @return
     */
    protected boolean enableRightSliding(){
        return false;
    }

源代碼


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章