ユニバーサルプロジェクトの共有プロジェクトにカスタムコントロールを作成し、画像が切れないようにスクロール位置を調整する方法を解説する。
powered by Insider.NET
画面をスクロールさせたときに停止位置を制御したいと思ったことはないだろうか? 例えば、複数の画像を横スクロールで見せるUI(ユーザーインターフェース)をユニバーサルプロジェクトで作っているときだ。Windowsの広い画面ではよいのだが、Phoneの狭い画面では画像がきっちり(途中で切れたりせずに)表示される位置でスクロールを止めたくなるだろう。本稿ではその方法を説明する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #87」からダウンロードできる。
本稿では例として、複数の画像を横スクロールで見せるUIを考えてみる。ScrollViewerコントロール(Windows.UI.Xaml.Controls名前空間)を使って素直に作ると、スクロールできる範囲内ならどこでも止められてしまう(次の画像)。
画面の広いWindowsではこれでも困らない。しかし、画面の狭いWindows Phoneでは、正確にスクロール位置を操作しないときちんと画像が見られない。これはエンドユーザーにとってストレスだろう。Windows Phoneでは指で慣性を付けてスワイプするだけで、次の画像がきちんと表示されることが望ましい。また、Windowsでも、複数アプリを並べて表示しているときには同じことがいえる。
解決策として画面幅が狭いときにはFlipViewコントロール(Windows.UI.Xaml.Controls名前空間)に切り替えるという手段も考えられるが、かなり面倒だ。画像がきちんと表示される位置でスクロールが停止してくれたら、どれだけ楽だろうか。
ユニバーサルプロジェクトを使ってユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Express 2013 for Windowsを使っている。
*1 SLAT対応ハードウェアは、Windows Phone 8.1エミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能だ。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウェアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。
*2 事前には「Windows 8.1 Update 1」と呼ばれていたアップデート。スタート画面の右上に検索ボタンが(環境によっては電源ボタンも)表示されるようになるので、適用済みかどうかは簡単に見分けられる。ちなみに公式呼称は「the Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 update that is dated April, 2014」というようである。
*3 Windows Phone 8.1エミュレーターを使用しないのであれば、32bit版のWindows 8.1でもよい。
*4 マイクロソフトのダウンロードページから誰でも入手できる(このURLはUpdate 3のもの)。
*5 本稿に掲載したコードを試すだけなら、無償のExpressエディションで構わない。Visual Studio Express 2013 with Update 3 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsストアアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。
本稿では、紛らわしくない限り次の略称を用いる。
Visual Studio 2013 Update 2では、残念なことにVB用のユニバーサルプロジェクトのテンプレートは含まれていない*6。そのため、本稿で紹介するVBのコードはユニバーサルプロジェクトではなく、PCL(ポータブルクラスライブラリ)を使ったプロジェクトのものである*7。
*6 VB用のユニバーサルプロジェクトは、来年にリリースされるといわれているVisual Studio「14」からの提供となるようだ。「Visual Studio UserVoice」(英語)のリクエストに対する、6月18日付けの「Visual Studio team (Product Team, Microsoft)」からの回答による。
*7 Visual Studio 2013 Update 2のVBでユニバーサルWindowsアプリを作る場合のお勧めは、「The Visual Basic Team」のブログ記事(英語)によれば、PCLを使う方法のようである。PCLに置いたものは、コードだけでなくXAML(画面)やリソースディクショナリなども共通に利用できる。そこで別途公開のサンプルコードでも、VBはWindows用/Phone用/共通コード(PCL)の3プロジェクト構成とした。ユニバーサルプロジェクトで作らなくてもユニバーサルWindowsアプリはリリースできるのである(「WinRT/Metro TIPS:ユニバーサルプロジェクトで開発するには?」参照)。
ScrollViewerコントロールのHorizontalSnapPointsTypeプロパティなどを利用すればよい。
ただし、先にお断りしておくが、有効なのはタッチ操作とマウスのホイール操作の場合である(スクロールバーを操作したときには効かない)。また、画像などを配置するコンテナーとして、StackPanelコントロール(Windows.UI.Xaml.Controls名前空間)を使わねばならない(後述の「IScrollSnapPointsInfoインターフェースについて」を参照)。
それではまず、冒頭の画像に示した横スクロールするUIから作っていこう。ユニバーサルプロジェクトの共有プロジェクトに新しくユーザーコントロールを作り、そこに次のようなコードを記述する(横スクロールするUIの部分のみを示す)。
<UserControl.Resources>
<Style TargetType="Image">
<Setter Property="Width" Value="360" />
<Setter Property="MinHeight" Value="400" />
<Setter Property="Margin" Value="10,0,10,0" />
<Setter Property="VerticalAlignment" Value="Top" />
</Style>
</UserControl.Resources>
……省略……
<ScrollViewer x:Name="ScrollViewer1" ……省略……
HorizontalScrollBarVisibility="Auto" HorizontalScrollMode="Auto"
VerticalScrollBarVisibility="Hidden" VerticalScrollMode="Disabled">
<StackPanel Orientation="Horizontal" Margin="0,40,360,0">
<Image Source="Assets/……省略……"/>
……省略……
<Image Source="Assets/……省略……"/>
</StackPanel>
</ScrollViewer>
上のコードでは、冒頭に載せた画像のように、スクロール途中のどこでも止めることができる。
画像の左端がScrollViewerコントロールの左端に合う位置でスクロールが止まるようにするには、次のコードのようにする。
this.ScrollViewer1.HorizontalSnapPointsType = SnapPointsType.MandatorySingle;
this.ScrollViewer1.HorizontalSnapPointsAlignment = SnapPointsAlignment.Near;
Me.ScrollViewer1.HorizontalSnapPointsType = SnapPointsType.MandatorySingle
Me.ScrollViewer1.HorizontalSnapPointsAlignment = SnapPointsAlignment.Near
上で設定しているプロパティの主要な値を次の表に示しておく。
値 | 説明 |
---|---|
SnapPointsType.None | 任意の場所で止まる(デフォルト) |
SnapPointsType.Mandatory | 必ずスナップポイントで止まる(慣性が付いているときは、複数アイテムをまたいでスクロールする) |
SnapPointsType.MandatorySingle | 必ず次のスナップポイントで止まる(慣性が付いていても、次のアイテムで止まる) |
値 | 説明 |
---|---|
SnapPointsAlignment.Near | アイテムの左端がScrollViewerコントロールの左端に一致する位置で止まる(デフォルト) |
SnapPointsAlignment.Far | アイテムの右端がScrollViewerコントロールの右端に一致する位置で止まる |
上で作ったユーザーコントロールをWindowsとPhoneの画面に配置して実行してみると、次の画像のようになる。[スナップあり]を有効にすると、タッチ操作(またはマウスホイール操作)でスクロールさせたときに、左端の画像の左端がScrollViewerコントロールの左端に合う位置に必ず止まる。
ScrollViewerコントロールに対してスクロール停止位置を座標で指定できれば便利だと思えるのだが、残念ながらそうなってはいない。実際のところは、IScrollSnapPointsInfoインターフェース(Windows.UI.Xaml.Controls.Primitives名前空間)を実装したコントロールの位置に合わせて止まるという仕組みになっているのだ(正確にはコントロールの位置ではなく、IScrollSnapPointsInfoインターフェースのGetIrregularSnapPointsメソッド/GetRegularSnapPointsメソッドが返す「スナップポイント」の位置に止まる)。
そして、IScrollSnapPointsInfoインターフェースを備えているコンテナコントロールは、今のところはStackPanelコントロール(Windows.UI.Xaml.Controls名前空間)だけである(他にItemsPresenterコントロール(Windows.UI.Xaml.Controls名前空間)がある)。それで本稿ではStackPanelコントロールを使ったのだ*8。
*8 GridViewコントロールなどでスナップポイントを利用したいとき、簡易的にはアイテムテンプレートにStackPanelコントロールを使えばよい。その手法は、ブログ記事「The taming of the Metro GridView」(英語)などで紹介されている。
ScrollViewerコントロールの中にStackPanelコントロールを配置した場合には、ScrollViewerコントロールのプロパティでスクロール停止位置を制御できる。エンドユーザーに喜ばれるUIの構築に活用してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.