Android 提供向后的導(dǎo)航

2018-08-02 18:09 更新

編寫:Lin-H - 原文:http://developer.android.com/training/implementing-navigation/temporal.html

向后導(dǎo)航(Back navigation)是用戶根據(jù)屏幕歷史記錄返回之前所查看的界面。所有Android設(shè)備都可以為這種導(dǎo)航提供后退按鈕,所以你的app不需要在UI中添加后退按鈕。

在幾乎所有情況下,當(dāng)用戶在應(yīng)用中進(jìn)行導(dǎo)航時(shí),系統(tǒng)會(huì)保存activity的后退棧。這樣當(dāng)用戶點(diǎn)擊后退按鈕時(shí),系統(tǒng)可以正確地向后導(dǎo)航。但是,有少數(shù)幾種情況需要手動(dòng)指定app的后退操作,來提供更好的用戶體驗(yàn)。

Back Navigation 設(shè)計(jì)

在繼續(xù)閱讀篇文章之前,你應(yīng)該先在Navigation design guide中對(duì)后退導(dǎo)航的概念和設(shè)計(jì)準(zhǔn)則有個(gè)了解。

手動(dòng)指定后退操作需要的導(dǎo)航模式:

下面說明如何在這幾種情況下實(shí)現(xiàn)恰當(dāng)?shù)南蚝髮?dǎo)航。

為深度鏈接合并新的后退棧

一般而言,當(dāng)用戶從一個(gè)activity導(dǎo)航到下一個(gè)時(shí),系統(tǒng)會(huì)遞增地創(chuàng)建后退棧。但是當(dāng)用戶從一個(gè)在自己的任務(wù)中啟動(dòng)activity的深度鏈接進(jìn)入app,你就有必要去同步新的后退棧,因?yàn)樾碌腶ctivity是運(yùn)行在一個(gè)沒有任何后退棧的任務(wù)中。

例如,當(dāng)用戶從通知進(jìn)入你的app中的深層activity時(shí),你應(yīng)該添加別的activity到你的任務(wù)的后退棧中,這樣當(dāng)點(diǎn)擊后退(Back)時(shí)向上導(dǎo)航,而不是退出app。這個(gè)模式在Navigation design guide中有更詳細(xì)的介紹。

在manifest中指定父activity

從Android 4.1 (API level 16)開始,你可以通過指定<activity>元素中的android:parentActivityName屬性來聲明每一個(gè)activity的邏輯父activity。這樣系統(tǒng)可以使導(dǎo)航模式變得更容易,因?yàn)橄到y(tǒng)可以根據(jù)這些信息判斷邏輯Back Up navigation的路徑。

如果你的app需要支持Android 4.0以下版本,在你的app中包含Support Library并添加<meta-data>元素到<activity>中。然后指定父activity的值為android.support.PARENT_ACTIVITY,并匹配android:parentActivityName的值。

例如:

<application ... >
    ...
    <!-- main/home activity (沒有父activity) -->
    <activity
        android:name="com.example.myfirstapp.MainActivity" ...>
        ...
    </activity>
    <!-- 主activity的一個(gè)子activity -->
    <activity
        android:name="com.example.myfirstapp.DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName="com.example.myfirstapp.MainActivity" >
        <!-- 4.1 以下的版本需要使用meta-data元素 -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>
</application>

當(dāng)父activity用這種方式聲明,你就可以使用NavUtils API,通過確定每個(gè)activity相應(yīng)的父activity來同步新的后退棧。

在啟動(dòng)activity時(shí)創(chuàng)建后退棧

在發(fā)生用戶進(jìn)入app的事件時(shí),開始添加activity到后退棧中。就是說,使用TaskStackBuilder API定義每個(gè)被放到新后退棧的activity,不使用startActivity()。然后調(diào)用startActivities()來啟動(dòng)目標(biāo)activity,或調(diào)用getPendingIntent()來創(chuàng)建相應(yīng)的PendingIntent。

例如,當(dāng)用戶從通知進(jìn)入你的app中的深層activity時(shí),你可以使用這段代碼來創(chuàng)建一個(gè)啟動(dòng)activity并把新后退棧插入目標(biāo)任務(wù)的PendingIntent。

// 當(dāng)用戶選擇通知時(shí),啟動(dòng)activity的intent
Intent detailsIntent = new Intent(this, DetailsActivity.class);

// 使用TaskStackBuilder創(chuàng)建后退棧,并獲取PendingIntent
PendingIntent pendingIntent =
        TaskStackBuilder.create(this)
                        // 添加所有DetailsActivity的父activity到棧中,
                        // 然后再添加DetailsActivity自己
                        .addNextIntentWithParentStack(upIntent)
                        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendingIntent);
...

產(chǎn)生的PendingIntent不僅指定了啟動(dòng)哪個(gè)activity(被detailsIntent所定義)還指定了要插入任務(wù)(所有被detailsIntent定義的DetailsActivity)的后退棧。所以當(dāng)DetailsActivity啟動(dòng)時(shí),點(diǎn)擊Back向后導(dǎo)航至每一個(gè)DetailsActivity類的父activity。

Note:為了使addNextIntentWithParentStack()方法起作用,像上面所說那樣,你必須在你的manifest文件中使用android:parentActivityName(和相應(yīng)的元素<meta-data>)屬性聲明每個(gè)activity的邏輯父activity。

為Fragment實(shí)現(xiàn)向后導(dǎo)航

當(dāng)在app中使用fragment時(shí),個(gè)別的FragmentTransaction對(duì)象可以代表要加入后退棧中變化的內(nèi)容。例如,如果你要在手機(jī)上通過交換fragment實(shí)現(xiàn)一個(gè)master/detail flow(主/詳細(xì)流程),你就要保證點(diǎn)擊Back按鈕可以從detail screen返回到master screen。要這么做,你可以在提交事務(wù)(transaction)之前調(diào)用addToBackStack():

// 使用framework FragmentManager
// 或support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
                           .add(detailFragment, "detail")
                           // 提交這一事務(wù)到后退棧中
                           .addToBackStack()
                           .commit();

當(dāng)后退棧中有FragmentTransaction對(duì)象并且用戶點(diǎn)擊Back按鈕時(shí),FragmentManager會(huì)從后退棧中彈出最近的事務(wù),然后執(zhí)行反向操作(例如如果事務(wù)添加了一個(gè)fragment,那么就刪除一個(gè)fragment)。

Note:當(dāng)事務(wù)用作水平導(dǎo)航(例如切換tab)或者修改內(nèi)容外觀(例如在調(diào)整filter時(shí))時(shí),不要將這個(gè)事務(wù)添加到后退棧中。更多關(guān)于向后導(dǎo)航的恰當(dāng)時(shí)間的信息,詳見Navigation design guide。

如果你的應(yīng)用更新了別的UI元素來反應(yīng)當(dāng)前的fragment狀態(tài),例如action bar,記得當(dāng)你提交事務(wù)時(shí)更新UI。除了在提交事務(wù)的時(shí)候,在后退棧發(fā)生變化時(shí)也要更新你的UI。你可以設(shè)置一個(gè)FragmentManager.OnBackStackChangedListener來監(jiān)聽FragmentTransaction什么時(shí)候復(fù)原:

getSupportFragmentManager().addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
            public void onBackStackChanged() {
                // 在這里更新你的UI
            }
        });

為WebView實(shí)現(xiàn)向后導(dǎo)航

如果你的應(yīng)用的一部分包含在WebView中,可以通過瀏覽器歷史使用Back。要這么做,如果WebView有歷史記錄,你可以重寫onBackPressed()并代理給WebView:

@Override
public void onBackPressed() {
    if (mWebView.canGoBack()) {
        mWebView.goBack();
        return;
    }

    // 否則遵從系統(tǒng)的默認(rèn)操作.
    super.onBackPressed();
}

要注意當(dāng)使用這一機(jī)制時(shí),高動(dòng)態(tài)化的頁面會(huì)產(chǎn)生大量歷史。會(huì)生成大量歷史的頁面,例如經(jīng)常改變文件散列(document hash)的頁面,當(dāng)要退出你的activity時(shí),這會(huì)使你的用戶感到繁瑣。

更多關(guān)于使用WebView的信息,詳見Building Web Apps in WebView。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)