如何在横屏模式下并排显示两个碎片(fragment)?

3
我有一个托管ListFragmentA的Activity1。
在单击列表项时,我启动托管ListFragmentB的Activity2。
无论是纵向还是横向,一次只能看到一个列表。
当我处于横向模式(或者在平板电脑上),我想同时看到两个片段。
也就是说,在显示器左侧有ListFragmentA,在右侧有ListFragmentB。这样,当用户从ListFragmentA中选择项目时,会显示ListFragmentB中的正确数据。
怎么做呢?以我看来,通过横向模式下的布局显得繁琐 / 错误,并且我不确定它是如何实现的。
有没有好的示例供我参考?

也许这会有所帮助 http://www.mysamplecode.com/2012/08/android-fragment-example.html - N Kaushik
1个回答

1

竖屏模式下的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) {
                                                // In dual-pane mode, the list view highlights the selected item.
                                                getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
                                                // Make sure our UI is in the correct state.
                        showDetails(mCurCheckPosition);
                                    } else {

FragmentLayout(主活动)在onCreate()期间通常方式应用布局:

public class FragmentLayout extends Activity {

            @Override
            protected void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);

                        // root view inflated
                        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;

        // onActivityCreated() is called when the activity's onCreate() method
        // has returned.

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);

            // You can use getActivity(), which returns the activity associated
            // with a fragment.
            // The activity is a context (since Activity extends Context) .

            Toast.makeText(getActivity(), "TitlesFragment:onActivityCreated",
                    Toast.LENGTH_LONG).show();

            // Populate list with our static array of titles in list in the
            // Shakespeare class
            setListAdapter(new ArrayAdapter<String>(getActivity(),
                    android.R.layout.simple_list_item_activated_1,
                    Shakespeare.TITLES));

            // Check to see if we have a frame in which to embed the details
            // fragment directly in the containing UI.
            // R.id.details relates to the res/layout-land/fragment_layout.xml
            // This is first created when the phone is switched to landscape
            // mode

            View detailsFrame = getActivity().findViewById(R.id.details);

            Toast.makeText(getActivity(), "detailsFrame " + detailsFrame,
                    Toast.LENGTH_LONG).show();

            // Check that a view exists and is visible
            // A view is visible (0) on the screen; the default value.
            // It can also be invisible and hidden, as if the view had not been
            // added.
            //
            mDualPane = detailsFrame != null
                    && detailsFrame.getVisibility() == View.VISIBLE;

            Toast.makeText(getActivity(), "mDualPane " + mDualPane,
                    Toast.LENGTH_LONG).show();

            if (savedInstanceState != null) {
                // Restore last state for checked position.
                mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
            }

            if (mDualPane) {
                // In dual-pane mode, the list view highlights the selected
                // item.
                getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
                // Make sure our UI is in the correct state.
                showDetails(mCurCheckPosition);
            } else {
                // We also highlight in uni-pane just for fun
                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;

            // The basic design is mutli-pane (landscape on the phone) allows us
            // to display both fragments (titles and details) with in the same
            // activity; that is FragmentLayout -- one activity with two
            // fragments.
            // Else, it's single-pane (portrait on the phone) and we fire
            // another activity to render the details fragment - two activities
            // each with its own fragment .
            //
            if (mDualPane) {
                // We can display everything in-place with fragments, so update
                // the list to highlight the selected item and show the data.
                // We keep highlighted the current selection
                getListView().setItemChecked(index, true);

                // Check what fragment is currently shown, replace if needed.
                DetailsFragment details = (DetailsFragment) getFragmentManager()
                        .findFragmentById(R.id.details);
                if (details == null || details.getShownIndex() != index) {
                    // Make new fragment to show this selection.

                    details = DetailsFragment.newInstance(index);

                    Toast.makeText(getActivity(),
                            "showDetails dual-pane: create and replace fragment",
                            Toast.LENGTH_LONG).show();

                    // Execute a transaction, replacing any existing fragment
                    // with this one inside the frame.
                    FragmentTransaction ft = getFragmentManager()
                            .beginTransaction();
                    ft.replace(R.id.details, details);
                    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                    ft.commit();
                }

            } else {
                // Otherwise we need to launch a new activity to display
                // the dialog fragment with selected text.
                // That is: if this is a single-pane (e.g., portrait mode on a
                // phone) then fire DetailsActivity to display the details
                // fragment

                // Create an intent for starting the DetailsActivity
                Intent intent = new Intent();

                // explicitly set the activity context and class
                // associated with the intent (context, class)
                intent.setClass(getActivity(), DetailsActivity.class);

                // pass the current position
                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) {
        // If the screen is now in landscape mode, we can show the
        // dialog in-line with the list so we don't need this activity.
        finish();
        return;
    }

    if (savedInstanceState == null) {
        // During initial setup, plug in the details fragment.

        // create fragment
        DetailsFragment details = new DetailsFragment();

        // get and set the position input by user (i.e., "index")
        // which is the construction arguments for this fragment
        details.setArguments(getIntent().getExtras());

        //
        getFragmentManager().beginTransaction()
                .add(android.R.id.content, details).commit();
    }
}

}

DetailsFragment

该片段首先被创建。 片段生命周期确保调用onCreateView()来构建片段的布局。 它使用一个文本视图构建片段- text.setText(Shakespeare.DIALOGUE [getShownIndex()]) - 并将其附加到滚动器(ScrollView),然后返回(并呈现)绘制的视图。

    // This is the secondary fragment, displaying the details of a particular
    // item.        

    public static class DetailsFragment extends Fragment {

                **snippet**

                public int getShownIndex() {
                            return getArguments().getInt("index", 0);
                }

                // The system calls this when it's time for the fragment to draw its
                // user interface for the first time. To draw a UI for your fragment,
                // you must return a View from this method that is the root of your
                // fragment's layout. You can return null if the fragment does not
                // provide a UI.

                // We create the UI with a scrollview and text and return a reference to
                // the scoller which is then drawn to the screen

                @Override
                public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                        Bundle savedInstanceState) {

                    **snippet**

                        // programmatically create a scrollview and textview for the text in
                        // the container/fragment layout. Set up the properties and add the view

                        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;
                }
    }

你为构建一个看似完整的示例付出了很多努力,但却省略了很多细节。这些「snippet」是怎么回事? - DSlomer64

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接