Skip to content

Most visited

Recently visited

navigation

柔軟な UI フローを実装する

アプリケーションが現在表示しているレイアウトによって、UI フローが異なる場合があります。 たとえばアプリケーションがデュアルペイン モードである場合、左ペインでアイテムをクリックすると右ペインにコンテンツが表示されます。シングルペイン モードの場合は、コンテンツは(別のアクティビティで)そのペイン自体に表示されます。

現在のレイアウトを特定する

各レイアウトの実装は多少異なるため、最初に行う必要があることの 1 つは、ユーザーが現在表示しているレイアウトを特定することです。 たとえば、ユーザーが「シングルペイン モード」が「デュアルペイン モード」かを確認する場合があります。 そのためには、特定のビューが存在し、表示されているかどうかを照会します。

public class NewsReaderActivity extends FragmentActivity {
    boolean mIsDualPane;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        View articleView = findViewById(R.id.article);
        mIsDualPane = articleView != null &&
                        articleView.getVisibility() == View.VISIBLE;
    }
}

このコードでは「article」ペインが使用可能かどうかを照会していることに注意してください。これは、特定のレイアウトの照会をハードコードするよりもはるかに柔軟です。

さまざまなコンポーネントの存在に対応する別の例として、それらのコンポーネントに対して操作を実行する前にそれらが使用可能かどうかを確認することがあります。 たとえばニュース リーダーのサンプルアプリにはメニューを開くボタンがありますが、そのボタンは Android 3.0 よりも前のバージョンで実行している場合にのみ存在します(その機能は API レベル 11 以上では ActionBar に引き継がれているため)。 したがって、このボタンのイベント リスナーを追加するために、次のことを実行できます。

Button catButton = (Button) findViewById(R.id.categorybutton);
OnClickListener listener = /* create your listener here */;
if (catButton != null) {
    catButton.setOnClickListener(listener);
}

現在のレイアウトに対応する

一部のアクションは現在のレイアウトに応じて結果が異なる場合があります。たとえばニュース リーダーのサンプルでは、見出しリストから見出しをクリックすると、UI がデュアルペイン モードの場合には右側のペインで記事が開きますが、UI がシングルペイン モードの場合には別のアクティビティが起動されます。

@Override
public void onHeadlineSelected(int index) {
    mArtIndex = index;
    if (mIsDualPane) {
        /* display article on the right pane */
        mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
    } else {
        /* start a separate activity */
        Intent intent = new Intent(this, ArticleActivity.class);
        intent.putExtra("catIndex", mCatIndex);
        intent.putExtra("artIndex", index);
        startActivity(intent);
    }
}

同様に、アプリがデュアルペイン モードの場合にはナビゲーション用のタブがあるアクションバーが設定され、アプリがシングルペイン モードの場合にはスピナー ウィジェットでのナビゲーションが設定されます。 したがって、どちらのケースに該当するかもコードでチェックする必要があります。

final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" };

public void onCreate(Bundle savedInstanceState) {
    ....
    if (mIsDualPane) {
        /* use tabs for navigation */
        actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS);
        int i;
        for (i = 0; i < CATEGORIES.length; i++) {
            actionBar.addTab(actionBar.newTab().setText(
                CATEGORIES[i]).setTabListener(handler));
        }
        actionBar.setSelectedNavigationItem(selTab);
    }
    else {
        /* use list navigation (spinner) */
        actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST);
        SpinnerAdapter adap = new ArrayAdapter(this,
                R.layout.headline_item, CATEGORIES);
        actionBar.setListNavigationCallbacks(adap, handler);
    }
}

フラグメントを他のアクティビティで再利用する

複数画面用の設計での繰り返しパターンには、一部の画面構成ではペインとして、別の構成では個別のアクティビティとして実装されるインターフェースの一部が使用されます。 たとえばニュース リーダーのサンプルでは、ニュース記事のテキストは大きい画面では右側のペインに表示されますが、小さい画面では別のアクティビティです。

このような場合、通常は同じ Fragment サブクラスを複数のアクティビティで再利用することによって、コードの重複を避けることができます。 たとえば ArticleFragment はデュアルペイン レイアウトで使用されます。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>

また、小さい画面のアクティビティ レイアウト内で(レイアウトなしで)再利用されます(ArticleActivity)。

ArticleFragment frag = new ArticleFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();

これは XML レイアウトでフラグメントを宣言するのと同じ効果がありますが、この場合には XML レイアウトは不要です。このアクティビティのコンポーネントは記事のフラグメントのみであるためです。

フラグメントを設計する際に注意する必要がある重要な点として、特定のアクティビティとの強い結び付きを作らないということがあります。 そのために通常は、フラグメントとそのホスト アクティビティとのやり取りで使用する必要がある方法すべてを抽象化するインターフェースを定義し、ホスト アクティビティはそのインターフェースを実装します。

たとえば、ニュース リーダーのアプリの HeadlinesFragment はそのようになっています。

public class HeadlinesFragment extends ListFragment {
    ...
    OnHeadlineSelectedListener mHeadlineSelectedListener = null;

    /* Must be implemented by host activity */
    public interface OnHeadlineSelectedListener {
        public void onHeadlineSelected(int index);
    }
    ...

    public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) {
        mHeadlineSelectedListener = listener;
    }
}

そうすると、ユーザーが見出しを選択したときに、フラグメントは(ハードコードされた特定のアクティビティに通知するのではなく)ホスト アクティビティによって指定されたリスナーに通知します。

public class HeadlinesFragment extends ListFragment {
    ...
    @Override
    public void onItemClick(AdapterView<?> parent,
                            View view, int position, long id) {
        if (null != mHeadlineSelectedListener) {
            mHeadlineSelectedListener.onHeadlineSelected(position);
        }
    }
    ...
}

この手法については、タブレットとハンドセットのサポートで詳細に説明されています。

画面構成の変更を処理する

インターフェースの個々の部分を実装するために個別のアクティビティを使用している場合、インターフェースの一貫性を維持するために、特定の構成変更(回転変更など)に対応する必要がある場合があることに注意してください。

たとえば Android 3.0 以降を実行している通常の 7 インチ タブレットでは、ニュース リーダーのサンプルは縦表示で実行されている場合は個別のアクティビティを使用してニュース記事を表示しますが、横表示では 2 ペイン レイアウトを使用します。

つまり、ユーザーが縦表示を使用していて、記事を表示するためのアクティビティが画面上にある場合は、画面の向きが横表示に変わったことを検出して、コンテンツが 2 ペイン レイアウトで表示されるように、アクティビティを終了してメイン アクティビティに戻ることで適切に対応する必要があります。

public class ArticleActivity extends FragmentActivity {
    int mCatIndex, mArtIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
        mArtIndex = getIntent().getExtras().getInt("artIndex", 0);

        // If should be in two-pane mode, finish to return to main activity
        if (getResources().getBoolean(R.bool.has_two_panes)) {
            finish();
            return;
        }
        ...
}
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

WeChat で Google Developers をフォローする

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience. (Dec 2017 Android Platform & Tools Survey)