竖屏模式下的fragment_layout.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/titles"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="edu.dartmouth.cs.FragmentLayout$TitlesFragment" />
</FrameLayout>
在横屏模式下,单个活动(FragmentLayout)处理两个片段。我们还将考虑以编程方式插入片段。请考虑横向 res/layout-land/fragment_layout。
横屏模式下的 fragment_layout.xml 如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal" >
<fragment
android:id="@+id/titles"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
class="edu.dartmouth.cs.FragmentLayout$TitlesFragment" />
<FrameLayout
android:id="@+id/details"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?android:attr/detailsElementBackground" />
</LinearLayout>
如果您在TitlesFragment:onActivityCreated()中注释掉下面显示的代码行(该行在FragmentLayout onCreate()返回时调用),则会看到从frame_layout上加载的空白。如果不添加该行,则DetailsFragment直到用户从列表中选择项目才被加载 - 在此时,DetailsFragment被创建并放置到FrameLayout中。
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
**snippet**
if (mDualPane) {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetails(mCurCheckPosition);
} else {
FragmentLayout(主活动)在onCreate()期间通常方式应用布局:
public class FragmentLayout extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
}
当用户在ListFragment中点击其中一个项目时,将调用onListItemClick()回调函数,该函数又会调用showDetails(position)以启动。
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(getActivity(),
"onListItemClick position is" + position, Toast.LENGTH_LONG)
.show();
showDetails(position);
}
TitlesFragment
该片段使用辅助函数显示所选项目的详细信息。
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Toast.makeText(getActivity(), "TitlesFragment:onActivityCreated",
Toast.LENGTH_LONG).show();
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1,
Shakespeare.TITLES));
View detailsFrame = getActivity().findViewById(R.id.details);
Toast.makeText(getActivity(), "detailsFrame " + detailsFrame,
Toast.LENGTH_LONG).show();
mDualPane = detailsFrame != null
&& detailsFrame.getVisibility() == View.VISIBLE;
Toast.makeText(getActivity(), "mDualPane " + mDualPane,
Toast.LENGTH_LONG).show();
if (savedInstanceState != null) {
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mDualPane) {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetails(mCurCheckPosition);
} else {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
getListView().setItemChecked(mCurCheckPosition, true);
}
}
管理方向翻转之间的状态
应用程序跟踪当前选中的选择,因此当它恢复时 - 例如在横向重新回到它时 - 它将使用片段生命周期中的onSaveInstanceState()作为最后一个突出显示的位置。片段保存其当前动态状态,因此它可以在其进程的新实例中稍后重建。如果需要创建片段的新实例,则在此处放置的数据将在onCreate(Bundle)、onCreateView(LayoutInflater, ViewGroup, Bundle)和onActivityCreated(Bundle)中给出的Bundle中可用。在代码中,新片段在onActivityCreated()中恢复状态。这里的状态只是mCurCheckPosition。
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Toast.makeText(getActivity(), "onSaveInstanceState",
Toast.LENGTH_LONG).show();
outState.putInt("curChoice", mCurCheckPosition);
}
FragmentManager和Fragment事务
showDetails(position)是一个协助函数,用于显示所选项目的详细信息。可以通过在当前UI中显示一个片段或启动一个全新的Activity来实现。
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
getListView().setItemChecked(index, true);
DetailsFragment details = (DetailsFragment) getFragmentManager()
.findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
details = DetailsFragment.newInstance(index);
Toast.makeText(getActivity(),
"showDetails dual-pane: create and replace fragment",
Toast.LENGTH_LONG).show();
FragmentTransaction ft = getFragmentManager()
.beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
DetailsActivity: 竖屏模式处理
如之前所讨论的,如果用户点击列表项并且当前布局不包括R.id.details视图(DetailsFragment实现了这一点),那么应用程序会启动DetailsActivity活动来显示该项的内容。辅助函数在横向创建一个新的片段以在纵向上绘制细节,并启动一个活动(DetailsActivity)来管理详细片段——也就是创建一个新的DetailsFragment并使用FragmentManager将其添加到根视图中,如下所示。当屏幕处于纵向方向时,DetailsActivity嵌入DetailsFragment以显示所选播放摘要:
// 这是一个辅助活动,用于在屏幕大小不足以在一个活动中显示所有内容时显示用户选择的内容。
public static class DetailsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "DetailsActivity", Toast.LENGTH_SHORT).show();
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
finish();
return;
}
if (savedInstanceState == null) {
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction()
.add(android.R.id.content, details).commit();
}
}
}
DetailsFragment
该片段首先被创建。 片段生命周期确保调用onCreateView()来构建片段的布局。 它使用一个文本视图构建片段- text.setText(Shakespeare.DIALOGUE [getShownIndex()]) - 并将其附加到滚动器(ScrollView),然后返回(并呈现)绘制的视图。
public static class DetailsFragment extends Fragment {
**snippet**
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
**snippet**
ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 4, getActivity()
.getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
return scroller;
}
}