Android側(cè)滑踩坑記(仿IOS側(cè)滑finish頁面基于Slidr庫)

抓住人生中的一分一秒邻吭,勝過虛度中的一月一年!

背景

用過蘋果手機(jī)的都知道,蘋果沒有物理返回鍵,原生自帶側(cè)滑回退頁面api盛险,手勢操控起來很方便,但是Android去實現(xiàn)較為困難勋又,現(xiàn)微信苦掘、今日頭條等app各自都實現(xiàn)了側(cè)滑返回,于是也去研究了下如何實現(xiàn)赐写,目前GitHub上有很多開源的框架鸟蜡,有更好的輪子那必須用輪子了,但實現(xiàn)還是需要注意一些東西事項挺邀,下面給大家講解下如何正確去實現(xiàn)側(cè)滑回退功能

有很多類似的開源框架 暫舉五個
  1. SwipeBackLayout
  2. Slidr
  3. Snake
  4. and_swipeback
  5. ParallaxBackLayout
先看一個效果圖
cehua.gif
原理分析

側(cè)滑看似頂層Activity整體向右移動揉忘,然而并不是這樣的,android不支持倆個頁面聯(lián)動效果端铛,所以我們得想方設(shè)法在一個View中看到低層布局泣矛,和頂層布局倆個畫面,才能去做這種效果禾蚕,實現(xiàn)方案有倆種

不透明方案

在頂層Activity的DecorView中插入一個Layout您朽。監(jiān)聽側(cè)滑事件,移動頂層Activity的ContentView同時换淆,在該Layout的onDraw中調(diào)用View.draw(Canvas canvas)繪制下層ActivityContentView哗总。造成側(cè)滑透視到下層Activity的假象。
存在問題:當(dāng)布局變化或數(shù)據(jù)更新倍试,如橫豎屏切換讯屈、導(dǎo)航欄隱藏、窗口模式县习、分屏模式等涮母,該假象始終如一不會有對應(yīng)改變

透明方案

設(shè)置頂層Activity透明

<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>

然后監(jiān)聽側(cè)滑事件谆趾,移動頂層Activity的ContentView,即可真正透視到下層Activity的界面叛本。此時無論布局變化沪蓬、數(shù)據(jù)更新,都沒問題来候。BUT跷叉!該方案問題多如牛毛。营搅。性芬。
存在問題:windowIsTranslucenttrue會引起一系列的動畫問題,如前后臺切換動畫剧防、Activity回退動畫等植锉。網(wǎng)上有解決方案說設(shè)置"android:windowEnterAnimation""android:windowExitAnimation",經(jīng)測試并無卵用峭拘。同時俊庇,在SDK26(Android8.0)及以上,會與固定屏幕方向沖突造成閃退鸡挠。同時辉饱,下層的Activity只會進(jìn)入onPause狀態(tài),不會onStop拣展,等等問題

下面來說明下本人如何去實現(xiàn)了這個效果彭沼,以第二個Slidr來演示如何實現(xiàn),有能力的朋友可以自己寫一個側(cè)滑功能备埃,用其他框架遇到下述類似情況可以借簽處理方案
1姓惑、引入第三方庫
 implementation 'com.r0adkll:slidableactivity:2.0.6'
2、在BaseActivity的onCreate中初始化一下就可以了
 protected void initSlidable() {
        SlidrConfig config = new SlidrConfig.Builder()
                .edge(false)//true 代表邊界   false全屏觸摸
                .build();
        slidrInterface = Slidr.attach(this, config);
    }
3按脚、在AppTheme中加入支持透明屬性
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>

如此簡單就實現(xiàn)了...于毙,是不是很簡單,先別高興太早了辅搬,這只是第一步唯沮,
SDK26(Android8.0)及以上頁面同時設(shè)置了android:screenOrientation="portrait"和透明屬性,運行會出現(xiàn)Only fullscreen opaque activities can request orientation異常堪遂,大概意思為“只有不透明的全屏activity可以自主設(shè)置界面方向”介蛉,這樣說明Android8.0以上透明屬性和強(qiáng)制豎屏倆個只能取其一?現(xiàn)在的APP無特殊需求根本沒必要需要橫豎屏切換溶褪,只有豎屏效果币旧,這該怎么辦?后來經(jīng)過很長時間嘗試并終于解決了此問題

4竿滨、初探fullUser來實現(xiàn)強(qiáng)制豎屏(fullUser功能:允許使用用戶的任意方向 佳恬。自動旋轉(zhuǎn)打開:四個方向 。自動旋轉(zhuǎn)關(guān)閉:不旋轉(zhuǎn))

一般情況下強(qiáng)制豎屏我們都會這樣寫

 <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait" />

或者

  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//設(shè)置豎屏模式

其實我們設(shè)置android:screenOrientation="fullUser"于游,具體詳細(xì)大家可以自行百度下
所以我們將portrait替換成fullUser解決了上邊遺留下來的問題奔潰問題毁葱,SDK26(Android8.0)不再崩潰報異常,但是經(jīng)過機(jī)型測試贰剥,偶然間發(fā)現(xiàn)小米一款紅米手機(jī)強(qiáng)制豎屏效果沒適配倾剿,任然可以橫豎屏切換,那蚌成。前痘。。担忧,此方案就此作廢

5芹缔、最終behind來實現(xiàn)強(qiáng)制豎屏(behind功能:與Activity堆下的Activity方向相同 。自動旋轉(zhuǎn)打開:四個方向 瓶盛。自動旋轉(zhuǎn)關(guān)閉:不旋轉(zhuǎn))

behind此屬性說白了講是說與上個頁面屏幕旋轉(zhuǎn)方向相同最欠,這樣我們便可以邏輯轉(zhuǎn)換去思考下,第一個Activity設(shè)置強(qiáng)制豎屏惩猫,第二個頁面設(shè)置跟隨第一個屏幕方向?qū)傩?code>behind芝硬,首頁面MainActivity,登陸頁LoginActivity,閃屏頁SplashActivity都不需要實現(xiàn)側(cè)滑轧房,我們只給它們設(shè)置強(qiáng)制豎屏"portrait"拌阴,不設(shè)置透明屬性,因為這幾個頁面不需要側(cè)滑功能奶镶,這樣便可避免了倆者共存迟赃,經(jīng)過多方面測試,確實可以這樣厂镇,暫時沒發(fā)現(xiàn)問題

6捺氢、一些根本不需要實現(xiàn)側(cè)滑finish的頁面不設(shè)置透明屬性android:windowIsTranslucent

4.1也講了,再詳細(xì)說一下剪撬,比如LoginActivity摄乒,MainActivity等打開App第一個顯示的頁面其實沒必要具有側(cè)滑功能,上述我們是在全局主題AppTheme加的支持透明屬性android:windowIsTranslucent">true残黑,
所以應(yīng)當(dāng)修改為需要側(cè)滑的頁面增加該透明屬性馍佑,不需要側(cè)滑的頁面不設(shè)置android:windowIsTranslucent透明屬性,于是乎需要倆個主題

//主題屬性  全局狀態(tài)  Application中加入
 <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <!--<item name="colorPrimary">@color/colorTop</item>-->

        <item name="android:windowAnimationStyle">@style/activityAnimation</item>
    </style>
//不需要側(cè)滑頁面增加該theme
<style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
//需要側(cè)滑頁面增加該theme
    <style name="AppTheme.NoActionBar.Slidable" parent="AppTheme.NoActionBar">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

示例如下梨水,讓大家更好理解

 <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/logo"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/logo"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

 //不需要實現(xiàn)側(cè)滑的頁面
        <activity
            android:name=".ui.activity.MainActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar" />
 //需要實現(xiàn)側(cè)滑的頁面
 <activity
            android:name=".ui.login.ForgetPwdActivity"
            android:screenOrientation="behind"
            android:theme="@style/AppTheme.NoActionBar.Slidable" />

最后一步拭荤,每個第三方庫一般都會擴(kuò)展開放是否支持側(cè)滑finish頁面接口,我們將不需要側(cè)滑頁面設(shè)置成true
比如MainActivity中重寫BaseActivityinitSlidable方法疫诽,禁止初始化側(cè)滑屬性

 @Override
    protected void initSlidable() {
        // 禁止滑動返回
    }
7舅世、側(cè)滑狀態(tài)欄跟隨側(cè)滑頁面一起移動

這回運行完美旦委,能正常使用,豎屏效果和透明效果Android版本已兼容了雏亚,但是還會發(fā)現(xiàn)有點怪的地方是狀態(tài)欄,側(cè)滑后頁面變了缨硝,狀態(tài)欄還有那么一橫條,太難看了罢低,想到了設(shè)置統(tǒng)一的一個透明或者灰色查辩,但是還是難看,如何能夠做到側(cè)滑狀態(tài)欄跟隨側(cè)滑頁面一起移動呢网持?

思路:狀態(tài)欄可以設(shè)置顏色宜岛,也可以設(shè)置透明隱藏
所以不就簡單了功舀?辟汰,將狀態(tài)欄隱藏掉莉擒,頁面布局整體頂?shù)綘顟B(tài)欄上涨冀,頂部給一個狀態(tài)欄高度padding鹿鳖,為了版本兼容問題翅帜,api小于19不支持沉浸式涝滴,所以可以判斷版本>=19給整體頁面一個paddingTop=狀態(tài)欄高度
不就實現(xiàn)了側(cè)滑狀態(tài)欄跟隨側(cè)滑頁面一起移動歼疮?

 /**
     * 獲取狀態(tài)欄高度
     *
     * @param context context
     * @return 狀態(tài)欄高度
     */
    public static int getStatusBarHeight(Context context) {
        // 獲得狀態(tài)欄高度
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        return context.getResources().getDimensionPixelSize(resourceId);
    }
 /**
     * 為布局文件中新增的狀態(tài)欄布局設(shè)置背景色和高度
     */
    public static void setStatusViewAttr(View view, Activity activity) {
        if (view == null || activity == null) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
            layoutParams.height = StatusBarUtil.getStatusBarHeight(activity);
            view.setLayoutParams(layoutParams);
        }
    }

    /**
     * 增加View的paddingTop,增加的值為狀態(tài)欄高度 (智能判斷韩脏,并設(shè)置高度)
     */
    public static void setPaddingSmart(Context context, View view) {
        if (Build.VERSION.SDK_INT >= 19) {
            ViewGroup.LayoutParams lp = view.getLayoutParams();
            if (lp != null && lp.height > 0) {
                lp.height += getStatusBarHeight(context);//增高
            }
            view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context),
                    view.getPaddingRight(), view.getPaddingBottom());
        }
    }

運行一下便是上邊的gif圖片赡矢,想實現(xiàn)的朋友可以嘗試一下,但是還遺留下幾個問題八酒,但不影響整體效果

問題1:設(shè)置的跳轉(zhuǎn)頁面動畫效果不起作用

在整體AppTheme中設(shè)置<item name="android:windowAnimationStyle">@style/activityAnimation</item>
比如梦谜,左進(jìn)右出

<!--頁面打開關(guān)閉動畫-->
    <style name="activityAnimation" parent="@android:style/Animation">
        <!-- 新的Activity啟動時Enter動畫 -->
        <item name="android:activityOpenEnterAnimation">@anim/right_in</item>
        <!-- 新的Activity啟動時原有Activity的Exit動畫 -->
        <item name="android:activityOpenExitAnimation">@anim/left_out</item>
        <!-- 新的Activity退出時原有ActivityEnter動畫 -->
        <item name="android:activityCloseEnterAnimation">@anim/left_in</item>
        <!-- 新的Activity退出時Exit動畫 -->
        <item name="android:activityCloseExitAnimation">@anim/right_out</item>


        <item name="android:taskOpenEnterAnimation">@anim/right_in</item>
        <item name="android:taskOpenExitAnimation">@anim/left_out</item>
        <item name="android:taskCloseEnterAnimation">@anim/left_in</item>
        <item name="android:taskCloseExitAnimation">@anim/right_out</item>
        <item name="android:taskToFrontEnterAnimation">@anim/right_in</item>
        <item name="android:taskToFrontExitAnimation">@anim/left_out</item>
        <item name="android:taskToBackEnterAnimation">@anim/left_in</item>
        <item name="android:taskToBackExitAnimation">@anim/right_out</item>

    </style>

解決:可以更改一種實現(xiàn)動畫方式

@Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
        }
        return super.onCreateView(name, context, attrs);
    }

    @Override
    public void finish() {
        super.finish();
        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
    }
問題2:有很多言論說onStop()不執(zhí)行耸棒?

由于被設(shè)置了<item name="android:windowIsTranslucent">true</item>Activity無法進(jìn)入onStop()生命周期,所以導(dǎo)致ActivityWindow無法回收,所以在多個Activity疊加時會出現(xiàn)明顯的卡頓現(xiàn)象,目前并沒有特別好的解決辦法单山。
但是本人打印了下日志不管側(cè)滑返回米奸,物理鍵返回悴晰,onStop都有日志铡溪,大家可以測試下棕硫,本文章再繼續(xù)完善

問題3:最初選用android:screenOrientation="fullUser"來實現(xiàn)固定方向,但是暫時發(fā)現(xiàn)小米手機(jī)不適配

最終采用behind來實現(xiàn)固定頁面方向,behind此屬性說白了講是說與上個頁面屏幕旋轉(zhuǎn)方向相同袒啼,這樣我們便可以邏輯轉(zhuǎn)換去思考下,第一個Activity設(shè)置強(qiáng)制豎屏蚓再,第二個頁面設(shè)置跟隨第一個屏幕方向?qū)傩?code>behind,首頁面MainActivity对途,登陸頁LoginActivity,閃屏頁SplashActivity都不需要實現(xiàn)側(cè)滑,我們只給它們設(shè)置強(qiáng)制豎屏"portrait"实檀,不設(shè)置透明屬性惶洲,因為這幾個頁面不需要側(cè)滑功能按声,這樣便可避免了倆者共存恬吕,經(jīng)過多方面測試铐料,確實可以這樣,暫時沒發(fā)現(xiàn)問題

問題4:后續(xù)繼續(xù)補充

最后補充

現(xiàn)側(cè)滑已應(yīng)用到我的項目中篓跛,持續(xù)踩坑中膝捞,本所有優(yōu)化是基于 Slidr庫所操作,其他開源庫有類似問題可以借簽上述處理沐寺,有能力的朋友可以自己寫個側(cè)滑功能林艘,最后的最后建議用SwipeBackLayout庫,已經(jīng)比較成熟混坞,需要處理的問題少

祝大家開發(fā)愉快!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末北启,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拔第,更是在濱河造成了極大的恐慌咕村,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚊俺,死亡現(xiàn)場離奇詭異懈涛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)泳猬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門批钠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人得封,你說我怎么就攤上這事埋心。” “怎么了忙上?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵拷呆,是天一觀的道長。 經(jīng)常有香客問我,道長茬斧,這世上最難降的妖魔是什么腰懂? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮项秉,結(jié)果婚禮上绣溜,老公的妹妹穿的比我還像新娘。我一直安慰自己娄蔼,他們只是感情好怖喻,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岁诉,像睡著了一般锚沸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唉侄,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天咒吐,我揣著相機(jī)與錄音野建,去河邊找鬼属划。 笑死,一個胖子當(dāng)著我的面吹牛候生,可吹牛的內(nèi)容都是我干的同眯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼唯鸭,長吁一口氣:“原來是場噩夢啊……” “哼须蜗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起目溉,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤明肮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后缭付,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柿估,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年陷猫,在試婚紗的時候發(fā)現(xiàn)自己被綠了秫舌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡绣檬,死狀恐怖足陨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娇未,我是刑警寧澤墨缘,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響飒房,放射性物質(zhì)發(fā)生泄漏搁凸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一狠毯、第九天 我趴在偏房一處隱蔽的房頂上張望护糖。 院中可真熱鬧,春花似錦嚼松、人聲如沸嫡良。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寝受。三九已至,卻和暖如春罕偎,著一層夾襖步出監(jiān)牢的瞬間很澄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工颜及, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留甩苛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓俏站,卻偏偏與公主長得像讯蒲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子肄扎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容