次の方法で共有


モバイルの問題

Windows Phone ナビゲーション (第 2 部): 高度なナビゲーション

Yochay Kiriaty

コード サンプルのダウンロード

[MSDN マガジン最新の月刊コラム「モバイルの問題」は今月で締めくくります。Windows Phone 7 など、モバイル テクノロジの重要性が高まっているため、この重要なテクノロジのスキル向上を希望するすべてのレベルの開発者に向け、実用的で実際に活用できるアドバイスを提供する専門家たちを定期的に特集する予定です。これからの新連載コラムの方向付けにお力添えいただければとさいわいです。トピックに関するご意見、ご提案、ご質問については、mmeditor@microsoft.com (英語のみ) まで電子メールをお送りください。皆さんからのフィードバックをお待ちしています。—編集長]

先月は、Windows Phone ナビゲーション モデルと関連 API について説明しました (msdn.microsoft.com/magazine/gg650662 を参照してください)。今月は、高度なナビゲーション タスクを実現するためのヒントとテクニックを紹介し、Windows Phone の次の側面を取り上げます。

  • ナビゲーション API により、Navigate メソッドと GoBack メソッドを使用できます。これら 2 つのメソッドは、URL をナビゲーションの履歴 (戻るスタック) にプッシュまたはポップします。戻るスタックを管理する API は存在しないため、一時画面はプログラマが管理しなければなりません。一時画面とは、ユーザーが "戻る" ボタンを押したとき、再び表示するのは好ましくないダイアログやメッセージ (メッセージ プロンプトやログイン ダイアログ など) のことです。
  • Windows Phone では、ナビゲーションを 1 度に 1 つしかアクティブにできません。"ホームに移動する" 機能 (通常、ユーザーがホームに戻ることができるように、複数のページにショートカットとして用意されます) が必要であれば、GoBack メソッド呼び出しのシーケンスを 1 度に 1 つずつ順番に実行する必要があります。これはユーザー エクスペリエンスに影響します。
  • PhoneApplicationPage と PhoneApplicationFrame という 2 つのナビゲーション要素は、いずれもそのままではページ切り替えをサポートしません。

今回は、これらの要素に対処する実用的手法を理解できるよう、細かく見ていくことにしましょう。

一時コンテンツ

一時画面とは、ジャーナルの戻るスタック (ジャーナル履歴) に追加すべきではない画面 (ログイン ダイアログなど) のことです。ユーザーが、あるページからログイン ダイアログにナビゲーションを行った後、次のページに移動し、そこで "戻る" ボタンを押した場合、ログイン ダイアログに戻るのではなく、その前の画面に戻るのが好ましいナビゲーションです。

このような一時画面を作成して表示する方法は複数あります。わかりやすいのは、Silverlight のポップアップを使用して UI を表示する方法です。この手法には、次のように、小さな問題が 2 つあります。

  1. ポップアップはページ (携帯電話) の向きに対応していません。これは大きな問題ではありません。向きに対応したポップアップを作成するか、ビジュアル ツリーにポップアップを挿入し、ページの向きに応じたレイアウトを作成することができます。
  2. 全画面表示されるポップアップ内のコンテンツには、ハードウェア アクセラレータが適用されません。ログイン ダイアログの UI (および多くの一時ページ) については特に問題はありませんが、たくさんの項目をスクロールして表示するリスト ボックスを含むポップアップや、アニメーションで動くプログレス バー含むポップアップを想像してください。UI スレッドの応答性を最大限に高めるためには、ポップアップにハードウェア アクセラレータを適用したいと感じます。

このような小さな問題のため、UI をインラインにし、現在ページのコンテンツよりも高い z-index を指定して、ビジュアル ツリーに挿入することをお勧めします。次にその手順を示します。

  1. ビジュアル ツリーにインライン化するコンテンツをユーザー コントロールにパッケージ化します。これで、ツリーにコンテンツを挿入し、ページに表示することができます (ページの UI に混在することがなくなります)。
  2. UI を表示する PhoneApplicationPage で、"戻る" ボタンを押したときに、一時 UI に戻らないように、OnBackKeyPress コールバックまたは BackKeyPress イベントを処理します。
    1. 複数の状態 (展開、折りたたみなど) を持つカスタム コントロールでは、ホスト ページから状態をクエリし、"戻る" ボタンによる操作を適用可能かどうかを把握できるように、プロパティを公開します。たとえば、コントロール ツールキットの ListPicker には ListPickerMode プロパティが、ContextMenu には IsOpen プロパティがあります。
  3. 一時 UI を表示するときに、ページにアプリケーション バーを表示している場合は非表示にします。アプリケーション バーは OS によって表示され、不透明 (Opacity = 1.0) だとページのコンテンツ領域下部にその領域が確保されます。一時 UI を新しい画面として表示するシミュレーションを行う場合、アプリケーション バーを非表示にしておくことをお勧めします。
  4. 一時 UI に切り替えるとき、および一時 UI を閉じるときには、アプリケーションの他のユーザー エクスペリエンスに溶け込むように、必要に応じて、一時 UI にアニメーションを施します。

コード チュートリアル: 一時 UI 画面の参考として、このコラム付属のコード ダウンロードの TransientUISample.xaml.cs ファイルにコメントとして記述されている詳細手順を確認してください。

上記の要件のほとんどはわかりやすいものですが、手順 2.a. については説明が必要です。アプリケーションの認定要件を満たすには、一時 UI を表示するときに、一時画面を表示する PhoneApplicationPage で前のページに戻るナビゲーションを行ってはいけません。代わりに、一時 UI を消去します。

このコラムの第 1 部では、OnBackKeyPress イベントや BackKeyPress イベントを処理して、ハードウェアの "戻る" ボタンによるナビゲーションを回避することについて説明しました。ページで 2 つの状態 (そのうちの 1 つは一時状態) を持つコントロールをホストしている場合、ページとコントロールの間で調整を少し (少なくとも認識できる程度に) 行う必要があります。ハンドシェイクを実装するには、次の手順を実行することをお勧めします。

  1. 複数の状態を持つカスタム コントロール (ListPicker など) では、ホストしているページで BackKeyPress イベントをサブスクライブし、適切に処理します。カスタム コントロールが一時状態にあれば、"戻る" ボタンの操作をキャンセルし、一時状態を解消します。
    1. これらのコントロールでは、必要な場合にのみ BackKeyPress イベントをサブスクライブします。BackKeyPress イベントのサブスクライブは必要になるまで遅延します。
    2. ここでは、コントロールでビジュアル ツリーを上方向に移動しながら、PhoneApplicationPage を探す方法を選択していますが、専門家 (コントロール ツールキット チームなど) によると、アプリケーションの RootVisual (PhoneApplicationFrame のこと) を使用して、そのコンテンツを調べることで、PhoneApplicationPage を見つけることができるそうです。当然、Silverlight アプリケーションには UI スレッドが 1 つしか存在しないことがわかっているため、この方法の方が効率的かつ安全です (コントロールやページのイベント ハンドラー内で、RootVisual が変化する可能性が低くなります)。
  2. カスタム コントロールと一時 UI ではプロパティを公開して、ホスト ページからその状態をクエリし、"戻る" ボタンによる操作を適用できる状態かどうかを把握できるようにします。たとえば、コントロール ツールキットの ListPicker には ListPickerMode プロパティが、ContextMenu には IsOpen プロパティがあります。   
  3. ホスト PhoneApplicationPage では、表示可能な一時コントロールまたは一時 UI を把握し、OnBackKeyPress イベント内でナビゲーションを実行する前に、これらをすべて確認する必要があります。OnBackKeyPress イベントが呼び出されてから、BackKeyPress イベントのハンドラーが呼び出されることを覚えておいてください。ホスト型のコントロールを使用して一時状態を処理する場合、Navigate メソッドを呼び出して、ハンドラーを先に進めないようにしてください。

"ホーム" ボタンのナビゲーション (戻るスタックのクリア)

他のモバイル プラットフォームに共通のユーザー エクスペリエンス パターンとして、ナビゲーションをショートカットし、特定のページに移動する "ホーム" ボタンがあります。Windows Phone ナビゲーション API では、このボタンを直接処理しません。実際、ユーザー エクスペリエンスのガイドラインでは、"ホーム" ボタンを使用しないように強く推奨されています。適切に設計された比較的フラットなナビゲーション構造を使用することをお勧めします。ナビゲーションの階層レベルが 2 ~ 3 レベルであれば、ハードウェアの "戻る" ボタンを数回押して戻るのも、画面上で "ホーム" ボタンを探してタッチするという計算されたジェスチャを実行するのも、簡単な操作です。とは言え、"ホーム" ボタンを使用することにした場合は、ナビゲーションを実装する際、次のような点を検討しておく必要があります。

  • Windows Phone ではナビゲーションを 1 度に 1 回しか実行できないことを忘れないでください。つまり、ナビゲーション階層の 4 レベル目で操作を行っていると、ホームに移動するため GoBack メソッドを連続 3 回呼び出す必要があります。ナビゲーションを同時実行することはできないため、次のナビゲーションを開始するには、実行中のナビゲーションが完了するまで (Navigated イベントが発生するまで) 待機しなければなりません。この "ナビゲーション シーケンス" では、ページの読み込みに時間がかかると、短時間遅延が発生する原因になります。また、戻るスタックをポップする間もページが表示されていると、"ちらつき" が発生する原因になります。
  • アプリケーション バーのアニメーションは OS によって実装されます。つまり、ページ間をループしながら移動すると、ループ内でのページ表示でアプリケーション バーがアニメーション化され、UI がちらつくことになります。

そこで、こうした "ホーム" ボタンによるナビゲーションの課題を解決する方法を紹介します。このコードはすべて、このコラム付属のダウンロードの、BackNavigationHelper クラスに実装されているのを確認できます。

  1. 戻るスタックをポップする間、画面から PhoneApplicationFrame (アプリケーションの RootVisual) を非表示にします。これで、UI のちらつきは回避されます (1 度だけちらつきますが、すべての画面で繰り返されることはありません)。
    1. ページの表示に長い時間がかかる場合は、アニメーションを含むポップアップを全画面表示にして、ユーザーが処理内容を把握できるようにします。
    2. ホームに移動するナビゲーションを開始する前にフラグを設定し、各ページでは OnNavigatedTo コールバックで多くの処理を実行しないよう指示します。戻るナビゲーションを実行する場合、ナビゲーションの完了時点でこれらのページはアンロードされます (そのため、これらのページで実行されている UI の処理は破棄されます)。
  2. IsVisible プロパティを false に設定して、巻き戻される各ページのアプリケーション バーを必要に応じて非表示にします。
    1. この処理は、アプリケーション バーが 100% 不透明 (Opacity = 1.0) のページでのみ実行する必要があります。
  3. スタックをさかのぼります。
    1. GoBack メソッドを呼び出します。
    2. まだ "ホーム" ページに到達していないければ、(RootVisual 上の) Navigated イベントをリッスンし、再び GoBack メソッドを呼び出します。

スタックをさかのぼるときには、すべてをリセットして既定値に戻します。

コード チュートリアル: このコラム付属のコード ダウンロードの HomeNavigationSamplePages フォルダーで、ページでの "ホームに移動する" ナビゲーションの例を確認できます。もちろん、興味深いコードは BackNavigationHelper クラスのコードですが、サンプルには、BackNavigationHelper クラスで有効にする必要があるオプション (フレームの非表示、アプリケーション バーの非表示、ジャーナルの検証など) を選択できる、BackNavConfig ページも含めています。

ページの遷移

最後に注目する最も高度なナビゲーションの概念は、ページの遷移に関するものです。ナビゲーションのコンテキストでの遷移とは、移動元ページから移動先ページへの引継ぎの考え方のことです。ページ遷移でも、ナビゲーションは先ほど説明した基になるナビゲーション フレームワークを使用して行われますが、ナビゲーションが行われるときに、ナビゲーションに関与する PhoneApplicationPages のコンテンツは、ページ引継ぎのシミュレーションを行うためにアニメーション化されます。

遷移のナビゲーションは少し複雑です。実際のところ、おばあちゃんのラザニアのようにお決まりのレシピはなく、好み (アプリケーションのニーズ) に応じて、ある程度 "微調整" が必要になります。とは言え、当然、サンプルやチュートリアルの他に、従うべき原則があります。

次の原則に従います。

  1. 先ほど説明した "戻る" ボタンの操作に関する原則にはすべて従います。遷移はナビゲーションの拡張にすぎません。認定を受けられなかった場合の代替策ではありません。
  2. 遷移のアニメーションのコンテキストと目的を理解します。Windows Phone には、明確に定義された一連の遷移が用意されており、そのほとんどに具体的なコンテキストと用途があります。アプリケーションに適切な遷移を実装できるように、目的とする用途を理解する必要があります。Jeff Arnold (Windows Phone のリード モーション デザイナー) は、すべてのアニメーションと遷移を簡単に録画しました。これは、各アニメーションの目的を理解するうえで必見です。このビデオは bit.ly/eBTkjD (英語) で公開されています。
  3. 遷移は高速かつ短時間で行います。
    1. 遷移は、ページ "から" 離れるときにも、別のページ "へ" 入るときにも発生します。これらの 2 つのフェーズにかかる時間を合計し、この合計時間を短くします。適切な上限は 300 ミリ秒です。
    2. 遷移中は、できるだけ多くの UI 処理を遅延します。ページでデータ バインドやコストがかかるレイアウト操作を回避できるかどうかを検討してください。画面遷移の直後に、回避した処理を実行します。

図 1 に、アニメーション、アニメーションの用途、遷移の方向、および関連メモをまとめます。

図 1 アニメーションのまとめ

アニメーション 用途 遷移の方向 遷移メモ
Turnstile ある領域から別の領域にユーザーを切り替えます。既定値はデバイス全体です。仕様では、遷移が行われることを強調するため、負荷が高い遷移です。 ForwardIn、ForwardOut、BackwardIn、BackwardOut これはよく使用する、実にわかりやすいアニメーションです。
Continuum ある領域から別の領域にユーザーを切り替えますが、連続性を認識できるようにします。ある領域から別の領域にコンテキストを移動します。ほとんど遷移が行われなかったように感じます。 In、Out Continuum はよく使用しますが、実装は困難です。コンテキストを連続して切り替える必要があります (2 つのページの間で UIElement が移動したように感じます)。
Swivel 一時 UI (ダイアログなど) に使用します。
遷移を行わないという点で他のアニメーションと異なりますが、ユーザーを同じ領域に留めるか、少なくともそう感じられるようにします。 ForwardIn、ForwardOut、FullScreenIn、FullScreenOut、BackwardIn、BackwardOut 遷移にはあまり使用しません。ダイアログに使用することがほとんどです。
Slide 一時 UI に使用します。既存のコンテンツに重ねて表示します。 SlideUpFadeIn、SlideUpFadeOut、SlideDownFadeIn、SlideDownFadeOut、SlideLeftFadeIn、SlideLeftFadeOut、SlideRightFadeIn、SlideRightFadeOut 一時 UI の遷移によく使用します。
Rotate 特定の方向および角度で画面を回転します。 In90Clockwise、In90CounterClockwise、In180Clockwise、In180CounterClockwise、Out90Clockwise、Out90CounterClockwise、Out180Clockwise、Out180CounterClockwise 遷移にはあまり使用しません。ページの向きを変えるために使用することがほとんどです。

前述の 3 つの原則を念頭において、ページ遷移のコーディングに着手します。Windows Phone コントロール ツールキットでは遷移がサポートされ、最も一般的な遷移にはストーリーボードがあります。

注: これ以降に説明する手順を実行するには、Windows Phone Toolkit 向けの Silverlight (silverlight.codeplex.com、英語) が必要になります。このコラムのコードは、2 月のリリースに対応するように作成しています (これ以降のリリースでも使用できます)。

ツールキットの遷移では TransitionFrame を使用します。TransitionFrame は PhoneApplicationFrame から継承されていますが、2 つのコンテンツ プレゼンターを含むカスタマイズされたテンプレートもあります (PhoneApplicationFrame にはコンテンツ プレゼンターは 1 つしかありません)。TransitionFrame では、その Content プロパティへの変更をリッスンして、古いコンテンツから新しいコンテンツ (ページ) に遷移します。

各 PhoneApplicationPage では、ツールキットの TransitionService クラスの添付プロパティを使用して、目的の遷移を判断します。ページあたり最大 4 つの遷移を指定できます (図 2 参照)。

図 2 指定できる 4 つのページ遷移

遷移 (プロパティ名) 説明
NavigationInTransition.Forward ページを先に進めるナビゲーションを使用して、このページに移動したときに呼び出されます。
NavigationInTransition.Backward ページを戻るナビゲーションを使用して、このページに移動したときに呼び出されます。
NavigationOutTransition.Forward ページを先に進めるナビゲーションを使用して、このページから離れたときに呼び出されます。
NavigationOutTransition.Backward ページを戻るナビゲーションを使用して、このページから離れたときに呼び出されます。

これらの遷移は、拡張可能な NavigationTransition クラスのインスタンスです。ツールキットには、TurnstileTranstion、SlideTransition、SwivelTransition、RotateTransition、および RollTransition の 5 つの組み込みの NavigationTransition が含まれています。前にも述べたように、このクラスは拡張可能なので、独自の遷移を追加できます。

ツールキットを使用して遷移をを実装する手順を次に示します。

1. リファレンスをダウンロードして、Silverlight コントロール ツールキットに追加します。

2. App.xaml.cs ファイルを編集し、アプリケーションの RootVisual フレームを TransitionFrame に置き換えます。 (図 3 参照)。

3. ページに遷移のプロパティを適用します (図 4 参照)。

図 3 App.xaml.cs ファイルを編集してアプリケーションの RootVisual フレームを置き換える

private void InitializePhoneApplication()
  {
    if (phoneApplicationInitialized)
        return;

    // Create the frame but don't set it as RootVisual yet; this allows the splash
    // screen to remain active until the application is ready to render.
    RootFrame = new Microsoft.Phone.Controls.TransitionFrame();
    RootFrame.Navigated += CompleteInitializePhoneApplication;

    // Handle navigation failures
    RootFrame.NavigationFailed += RootFrame_NavigationFailed;

    // Ensure we don't initialize again
    phoneApplicationInitialized = true;
  }

図 4 ページに遷移のプロパティを適用する

<phone:PhoneApplicationPage 
    x:Class="LWP.TransitionSamples.Turnstile"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True"  xmlns:toolkit=
    "clr-namespace:Microsoft.Phone.Controls;assembly=
    Microsoft.Phone.Controls.Toolkit"
  >

  <toolkit:TransitionService.NavigationInTransition>
    <toolkit:NavigationInTransition>
      <toolkit:NavigationInTransition.Backward>
        <toolkit:TurnstileTransition Mode="BackwardIn"/>
      </toolkit:NavigationInTransition.Backward>
      <toolkit:NavigationInTransition.Forward>
        <toolkit:TurnstileTransition Mode="ForwardIn"/>
      </toolkit:NavigationInTransition.Forward>
    </toolkit:NavigationInTransition>
  </toolkit:TransitionService.NavigationInTransition>
  <toolkit:TransitionService.NavigationOutTransition>
    <toolkit:NavigationOutTransition>
      <toolkit:NavigationOutTransition.Backward>
        <toolkit:TurnstileTransition Mode="BackwardOut"/>
      </toolkit:NavigationOutTransition.Backward>
      <toolkit:NavigationOutTransition.Forward>
        <toolkit:TurnstileTransition Mode="ForwardOut"/>
      </toolkit:NavigationOutTransition.Forward>
    </toolkit:NavigationOutTransition>
  </toolkit:TransitionService.NavigationOutTransition>

実用的な方法

要するに、Windows Phone Silverlight アプリケーションには、あるページから遷移できる Web に似たナビゲーション モデルと、前のページに戻ることができるようにジャーナル (履歴) があります。既定では、ナビゲーション モデルは使いやすく比較的完成度の高いものです。一時 UI、遷移、"ホームに移動する" 機能など、既定では実装されていない高度なナビゲーション タスクがいくつかありますが、この 2 部構成のコラムでは、このような高度なタスクを実装するうえで検討する必要がある設計上の考慮事項について説明し、簡潔で実用的な実装方法を紹介しました。

Yochay Kiriaty はマイクロソフトのシニア テクニカル エバンジェリストとして、Windows、Windows Phone などのクライアント テクノロジに取り組んでいます。『Introducing Windows 7 for Developers』(Microsoft Press、2009 年) および『Learning Windows Phone Programming』(O’Reilly Media、2011 年) の共著者でもあります。

Jaime Rodriguez はマイクロソフトのプリンシパル エバンジェリストとして、Silverlight、Windows Phone などの新たなクライアント テクノロジの導入に従事しています。Twitter (twitter.com/jaimerodriguez、英語) で彼をフォローできます。また、blogs.msdn.com/jaimer (英語) にブログを公開しています。

この記事のレビューに協力してくれた技術スタッフの Peter Torr に心より感謝いたします。