这是我所做的:在纵向模式下,我为列表视图和详细视图创建了相同的容器视图,但列表视图的宽度为 0dp。这样,当用户处于横向列表+详细信息模式时,如果他们向前导航、更改方向并按下后退按钮,列表和详细信息片段都会正确加载,但现在在纵向模式下您只能看到详细信息视图。
我并没有很熟练地使用它。如果您在纵向模式下导航,将列表转到详细信息,然后旋转到横向,我会显示列表和详细信息,但按下后退按钮只会再次显示列表。我的理念是恢复原样,并尽可能恢复冗余或丢失的窗格,让芯片掉到可能的地方。
但我认为你可以做得更好。让我们来处理每个案例。
用例 1:用户处于横向模式。用户导航到列表+详细信息窗格,并选择一个详细信息。如果用户旋转到纵向,他们应该只看到详细信息窗格。如果他们现在按返回,而不是列表+详细信息之前的 UI,他们应该只看到列表,然后导航回他们开始的位置。
用例 2:用户处于纵向模式。用户导航到列表屏幕,然后是详细信息屏幕。当用户旋转到横向模式时,他们应该看到列表+详细信息。当他们按下返回时,他们应该跳过返回堆栈上的列表屏幕。
我在平板电脑上的 GMail 应用上度过了一段美好的时光,它似乎做得很好。
让我们从布局 XML 开始。纵向和横向版本都将具有两个窗格,但在纵向中您只能看到一个:
layout/list_detail.xml
<LinearLayout
android:width="match_parent"
android:height="match_parent"
orientation="horizontal">
<FrameLayout
android:id="+id/list_pane"
android:width="match_parent"
android:height="match_parent"/>
<FrameLayout
android:id="+id/detail_pane"
android:width="match_parent"
android:height="match_parent"
android:visibility="gone"/>
</LinearLayout>
layout-landscape/list_detail.xml
<LinearLayout
android:width="match_parent"
android:height="match_parent"
orientation="horizontal">
<FrameLayout
android:id="+id/list_pane"
android:width="240dp"
android:height="match_parent"/>
<FrameLayout
android:id="+id/detail_pane"
android:width="0dp"
android:weight="1"
android:height="match_parent"/>
</LinearLayout>
这个想法是始终加载两个窗格中的片段,但在纵向模式下,您只能看到一个或另一个(通过切换哪个窗格可见和哪个窗格消失),而在横向模式下,您可以同时看到两者。
我将假设在横向模式下,您最初会使用列表中的第一项加载详细信息窗格。所以你总是有一个列表和一个细节,只是在肖像中你现在看不到细节。
首先,我们想知道我们的 UI 是处于列表模式还是详细模式,尤其是当我们从横向变为纵向时:
private boolean mListMode;
在onCreate() 中,我们将对其进行初始化:
mListMode = true;
在onCreateView()中,我们要恢复保存的模式状态(这里假设一个片段):
if (savedInstanceState != null) {
mListMode = savedInstanceState.getBoolean("listMode");
}
if (getResources().getBoolean(R.bool.is_portrait)) {
mListPane.setVisibility(mListMode ? View.VISIBLE : View.GONE);
mDetailPane.setVisibility(mListMode ? View.GONE : View.VISIBLE);
}
我们保存在里面
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean("listMode", mListMode);
super.onSaveInstanceState(outState);
}
现在列表项的点击逻辑如下:
if (mListMode) {
if (getResources().getBoolean(R.bool.is_portrait)) {
// TODO animate list -> detail
mDetailPane.setVisibility(View.VISIBLE);
mListPane.setVisibility(View.GONE);
}
mListMode = false; // a click puts UI in detail mode, even in landscape
}
您需要确保设置mListMode = false,以防用户在横向导航时单击详细信息窗格中的某些内容,因此如果他们旋转到纵向并回击,他们将看到详细信息窗格.
好的,现在你需要一个技巧来处理肖像的后退按钮。你可以在你的 UI 中做这样的事情(假设它是一个片段):
public boolean onBackPressed() {
if (getResources().getBoolean(R.bool.is_portrait) && ! mListMode) {
// TODO animate detail -> list
mDetailPane.setVisibility(View.GONE);
mListPane.setVisibility(View.VISIBLE);
mListMode = true;
return true; // we handled back button ourselves
}
return false; // we didn't handle back button
}
然后在你的活动中:
@Override
public void onBackPressed() {
ListDetailFragment listDetailFragment = (ListDetailFragment ) getFragmentManager().findFragmentByTag(LIST_DETAIL_TAG);
if (listDetailFragment != null && listDetailFragment.isResumed() && listDetailFragment.onBackPressed()) {
return;
}
super.onBackPressed();
}
我将把过渡动画留给读者作为练习。