一文理解Android微信右滑退出

效果圖

效果圖

act2是Main2Activity,act3是Main3Activity

原理

滾動

首先我們知道每個Activity展示的內(nèi)容一般都是DecorView去承載的,不知道的看下圖,其中狀態(tài)欄背景也包括在內(nèi):


DecorView

所以我們第一步,只需要滾動DecorView內(nèi)容或者平移DecorView就行了。

使上一個Activity可見

上面的Activity不可見其實是因為被當前Activity給擋住了。那問題來了。
Q:為什么我把布局顏色設置成透明背景,可還是看不到上面的Activity呢?
A:看上面的DecorView那張圖,我們Activity布局只是填充content里面的內(nèi)容,也就是說我們是被ContentFrameLayout包裹住的,Activity布局文件的根元素并不是Activity的根元素,由層級可知。我們的Activity被上層的Activity擋住,其實是因為DecorView具有背景顏色,我們只需要把它的背景色去掉就行了。

實現(xiàn)

第一步設置透明主題

 <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="CustomTheme" parent="AppTheme">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>
        <activity android:name=".Main2Activity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".Main3Activity"
            android:theme="@style/CustomTheme" />

我們把Main3Activity的DecorView背景色去掉了。

滾動DecorView內(nèi)容

這里我們使用滾動DecorView內(nèi)容而不是滾動整個DecorView。
首先大家需要搞懂一個View的ScrollByScrollTo是什么回事,參考Android scrollTo和scrollBy方法使用說明

Main3Activity.java

public class Main3Activity extends AppCompatActivity {


    /**
     * DecorView左邊滑出間距占屏幕寬度PRESENT_TO_FINISH時表示用戶需要退出當前Activity
     */
    private static final float PRESENT_TO_FINISH = 0.3f;


    /**
     * 用戶距離左邊MIN_EDGE_DISTANCE內(nèi)拖動有效
     */
    private static final int MIN_EDGE_DISTANCE = 100;


    /**
     * 屏幕寬度
     */
    private static float mScreenW = -1;

    /**
     * 用戶計算用戶在屏幕滑動的距離
     */
    private float mStartX = 0;

    /**
     * 當前是否允許拖動
     */
    private boolean mIsScrollEnable = false;

    /**
     * 當前Activity的DecorView
     */
    private View mDecorView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        // 初始化
        mDecorView = getWindow().getDecorView();
        if (mScreenW == -1) {
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay()
                    .getMetrics(metrics);
            mScreenW = metrics.widthPixels;
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mStartX = event.getX();
            if (mStartX < MIN_EDGE_DISTANCE) {
                // 距離左邊距離足夠小,設置為可拖動狀態(tài)
                mIsScrollEnable = true;
            }
        } else if (event.getAction() == MotionEvent.ACTION_MOVE && mIsScrollEnable) {
            // 滾動DecorView內(nèi)容
            float dX = event.getX() - mStartX;
            mStartX = event.getX();
            mDecorView.scrollBy((int) -dX, 0);
            return true;
        } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
            // 觸摸操作取消,重置
            mIsScrollEnable = false;

            // 根據(jù)當前滑動狀態(tài)判斷最終是滑到左邊還是滑到右邊(結束Activity)
            final int targetX = -mDecorView.getScrollX() / mScreenW > PRESENT_TO_FINISH ? (int) -mScreenW : 0;
            ValueAnimator animator = ValueAnimator.ofInt(mDecorView.getScrollX(), targetX);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mDecorView.scrollTo((Integer) animation.getAnimatedValue(), 0);
                }
            });
            animator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    if (targetX == -mScreenW) {
                        finish();
                    }
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            animator.start();
        }

        return super.onTouchEvent(event);
    }
}

寫在最后

這是最簡單最簡單的做法,無任何封裝與擴展,包括一些可能存在的滾動沖突也沒有去處理。大家可以封裝一個比較完善并且容易使用的庫,加入ListView之類的滑動沖突處理以及背景色透明漸變之類的,然后里面的xml代碼轉(zhuǎn)換成對應deJava代碼寫法。一句話使Activity實現(xiàn)該功能也是可以做到的。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容