こんにちはー!ニアです。
先週から開発していた、すぱこーRSSフィードリーダーのUWPアプリ「すぱこみっく!ユニバース」を先日、Windowsストアにリリースしました。
1. 本アプリを開発した理由
理由は2つあり、1つは先月末にWindowsストアの開発者アカウントを作成できたので、それを機に何か1つUWPアプリを作って公開しようと思ったからです。
実はというと、Windows 8がリリースされた時からWindowsストアアプリの開発に興味があり、何か作って公開したいと思っていたのですが、Windowsストアの開発者アカウントを作成するのにクレジットカードが必要で、当時持っていなかった私は、中々その機会に恵まれなかったのです。
(「え、学生がクレカ取得するのは簡単じゃないの?」と思う方もいるかもしれませんが、それについてはちょっと込み入った話になるので、ここでは控えさせてください。)
Windows 10をインストール後、開発したアプリを実機にサイドローディングしてぼちぼち動かしていましたが、今月になって、念願のストアアプリ開発&リリースがついに叶うことができました。
もう1つは、すぱこーRSSフィードがリリースされたのを見て、
と思ったからです。WebからRSSフィードを取得して情報を表示するプログラムは今まで沢山していたので、3週間あれば完成できる自信がありました。
プラットフォームでUWPを選んだのは、今まで学んだC#及びWPFの知識を活用できるのと、今年の1月にWindows Phoneを購入したので、モバイル用のアプリも作りたいなと思ったからです。UWPは1つプロジェクトでデスクトップ用やモバイル用に加えて、Xbox用や組み込み用アプリまで作れるのが魅力的ですね。
あとは、久しぶりにIT勉強会に参加したいので。
2. 本アプリの開発した期間
アプリを作り始めてから完成するまでが10日間、審査及びリリース処理が3日間なので、約2週間です。
2.1. 初日 : プロトタイプを作成
前年度のマスコットキャラ文化祭で作成したライブラリ、すぱーダの動作確認のために作ったプログラムをベースに、RSSフィードを表示するリストと漫画画像を表示するページを作りました。
↓
また、今年のマスコットアプリ文化祭で、すぱこーリーダーのアプリを作ることを宣言しました。
今年の #マスコットアプリ文化祭 は、すぱこーRSSリーダーのUWPアプリを作ろうかな pic.twitter.com/LOamryBNOD
— 智中ニア(Nia Tomonaka) (@nia_tn1012) 2016年10月3日
2.2. 3日目~4日目 : アプリを本格実装
(※2日目は別の用事があったので、何もしていません)
この期間にかけて、アプリのアクセントカラーをプログラミング生放送と同じ緑系に設定したり、RSS取得中の画面にプロ生ちゃんを召喚したりと、アプリを本格的に実装していきました。
2.3. 5~6日目 : RSSフィード一覧表示をGridViewに、漫画表示をFlipViewに変更
先日の記事に書いた通り、偶然通りかかった親に「漫画アプリを作っているの?」とツッコまれたのを機に、漫画表示部分にて左右にスワイプ操作で前後の話に移動できるように、改造してみようと思いました。
また、RSSフィード一覧のコントロールをListBoxからGridViewに換装してみました。スマホの画面であれば、ListBoxでも十分なのですが、画面の大きいタブレットやPCでは、各項目の右側で大きな余白ができるので、グリッド表示にした方がよいと思ったのです。
2.4. 7~8日目 : アプリ提出に向けて
アプリの開発始めて1週間後、アプリはほぼ完成したので、ストアのアップロードするためのパッケージを作成しました。
Windowsストア認定キットには無事に合格することができました。
※当時のスクリーンショットを取り忘れたので、本記事執筆時点で最近テストしたバージョンのものを載せています。
2.5. 9~10日目 : ページサイクルの見直し
しかし実際にアプリをリリースするには、2点の大きな課題がありました。
- GridViewでアイテムでないところをタップしても、コミックビューに飛ばされる
- SplitViewのDeisplayModeがCompactOverlayの状態でパネルを開き、パネル内のボタン(Button)を押して、PageのFrameから別のページに遷移すると、その処理を呼び出す前後でIsPaneOpenをfalseに設定したにもかかわらず、設定ページから戻った時にパネルが閉じない
前者については、TappedイベントをGridViewに設定するのではなく、そのItemsTemplate内のコントロールに設定することで解決しました。
問題は後者で、SplitViewのパネルを閉じるタイミングを変えても、問題は解決しませんでした。
// パターンA
private void SettingAboutButton_Click( object sender, RoutedEventArgs e ) {
Frame.Navigate( typeof( AppSettingView ) );
}
// パターンB
private void SettingAboutButton_Click( object sender, RoutedEventArgs e ) {
splitView.IsPaneOpen = false;
Frame.Navigate( typeof( AppSettingView ) );
}
// パターンC
private void SettingAboutButton_Click( object sender, RoutedEventArgs e ) {
Frame.Navigate( typeof( AppSettingView ) );
splitView.IsPaneOpen = false;
}
- パターンAでは、戻るボタンを2回押さないとページが戻らず(しかも設定ページから戻った時点でパネルは閉じない)
- パターンBでは、パネルは閉じるもののGridViewがフリーズする
- パターンCでは、戻るボタン1回で設定ページから戻れ、GridViewにも影響はなかったものの、SplitViewのパネルは閉じず
SplitViewと画面遷移についてインターネットで色々調べてみました。
ハンバーガーメニューで画面を遷移させるには?[Windows 10 UWPアプリ開発] (1/2) – @IT
この記事を見て、私はアプリのページ構成を少し変えることにしました。具体的には、メインとなるページにSplitViewを配置し、そのContentの中にすぱこーRSSフィード一覧やコミックビュー、設定画面をセットできるFrameコントロールを設置します。そのFrameがページ遷移を行うことで、前述のパネルが閉じない問題が発生しなくなりました。
とはいえ、現在申請しているバージョンでは、SplitViewのパネルにボタンを4つ入れて、どのページからでも遷移できるような構成にしたので、結果オーライね。
ちなみにメインのページに設置したタイトルテキストは、Frameが格納しているPageのTagとバインドし、ページ構成を変える前と同じように表示することができました。
2.6. 11~13日目 : アプリ提出~リリース
大きな問題も解決したので、アプリのパッケージをストアにアップロードし、12日深夜に申請を行いました。
先週から開発していた、すぱこーRSSフィードリーダーのUWPアプリを、たった今ストアに提出しました!
早ければ、今週中にリリースできます。 pic.twitter.com/APgA9M8LbM— 智中ニア(Nia Tomonaka) (@nia_tn1012) 2016年10月11日
※当時のスクリーンショットを取り忘れたので、本記事執筆時点で最近テストしたバージョンのものを載せています。
待つこと2日間、13日夕方に審査が通り、アプリをリリースできるようになりました。
アプリの審査、無事に通りましたヽ(^o^)丿
— 智中ニア(Nia Tomonaka) (@nia_tn1012) 2016年10月13日
その後リリースの申請をして14日の夕方、ついに開発したアプリがストアで公開されました。
実はというと、次のバージョン(Ver. 1.2.3)をすでにストアへ申請していて、審査の認定待ちです(笑)
3. 本アプリの工夫点(リリース時のバージョン)
本アプリは、RSSフィードリーダーとコミックリーダーの2つ機能を持っています。他にも、以下のような工夫をしています。
- SplitView+ハンバーガーボタンのデータバインディングによる、ナビゲーションメニューの実装
- GridViewでウィンドウの幅によるItemsTemplateの選択により、スマホとタブレット、PCでRSSフィード一覧の表示方法を切り替え(前者はリスト表示、後者はグリッド表示)
- コミックビューにはFlipViewを使用して、前後の話に切り替えられる
- 漫画画像はピンチイン・アウト及びダブルタップで拡大・縮小できる
- 取得したRSSフィードはローカルに保存され、次回以降の読み込みを高速化
- Webから取得した画像はメモリ内にキャッシュされ、アプリを閉じるまで保持
- アプリ起動時に、Web上にすぱこーの最新話があるかどうかチェックし、ある場合、トースト通知する
また、マスコットアプリ文化祭に参加するアプリということで、RSSフィード取得中とエラーダイアログ、トースト通知のアイコンにプロ生ちゃんを召喚しました。ちなみに次のバージョンでは、プロ生ちゃんが登場するエリアをさらに増やしました。
トースト通知のアイコンは、ノリで「プロ生ちゃん、マジ天丼」の画像を入れてみましたが、実際に表示させて面白かったので、アイコンとして採用しました。
天丼通知!#pronama pic.twitter.com/NRM7LAR21F
— 智中ニア(Nia Tomonaka) (@nia_tn1012) 2016年10月9日
天丼美味しいですよね。私は海老、イカ、帆立、獅子唐、椎茸が好きです。
4. 本アプリ開発で苦労したところ
前述のSplitViewの問題も苦労したところですが、もう1つ、FlipView上にセットした漫画画像の拡大・縮小処理(以下の3点)の実装で苦労しました。
- コミックビューを開いた時は、漫画の画像をウィンドウ中に収まるようにサイズを調整する
- 漫画画像はピンチイン・アウトで拡大・縮小できる
- 漫画画像をダブルタップで、原寸大⇔画面に収まるようにサイズ調整の切り替えができる
2.はScrollViewerを入れてズーム機能を有効にすることで実装出来ました。しかし1.が曲者で、ただズーム機能を有効にしただけでは、漫画の画像を拡大するとScrollViewerが画像を強制的に左にスナップしました。
そのためスマホでかつ漫画画像を拡大した状態で右側の方を読むには、スクロールした状態で画面に指をタッチし続けなければならなかったのです。こんなユーザーエクスペリエンスじゃ不便ですよね。
ScrollViewerのHorizontalScrollBarVisibilityをAuto(もしくはVisible)に設定すると、先ほどの強制スナップ問題は解決されましたが、今度はコミックビューを開いた時に、画像が原寸大の状態で表示されてウィンドウの中に収まらない問題が発生しました。画像を開くたびに一々縮小しなければならないのって・・・(汗)。こんなユーザーエクスペリエンスじゃ、ストレスが溜まってしまいますよね。
解決方法を探していた所、とてもいい記事が見つかりました(タイトル名を見て、もしかしたらと思い、記事を開いたらドンピシャでした)。
Why is my zoomable ScrollViewer snapping the image to the left? – igor ralic
その記事によると、ViewModelにPageの幅と高さを格納するプロパティ(※値のセット時にプロパティ変更通知をするようにします)を追加し、ImageのMaxWidthとMaxHeightにデータバインディングすることで解決するとのことでした。
実際に本アプリに実装してみると、問題は解決することができました。
// コンテンツの幅を表します。
private double contentWidth;
public double ContentWidth {
get { return contentWidth; }
set {
if( contentWidth != value ) {
contentWidth = value;
NotifyPropertyChanged();
}
}
}
// コンテンツの高さを表します。
private double contentHeight;
public double ContentHeight {
get { return contentHeight; }
set {
if( contentHeight != value ) {
contentHeight = value;
NotifyPropertyChanged();
}
}
}
本アプリでは、FlipViewの幅と高さをImageのMaxWidthとMaxHeightにデータバインディングしています。
<FlipView ItemsSource="{Binding Items}"
SelectedIndex="{Binding SelectedIndex}"
SizeChanged="FlipView_SizeChanged">
<FlipView.ItemTemplate>
<DataTemplate>
<ScrollViewer ZoomMode="Enabled" MinZoomFactor="1" MaxZoomFactor="10"
HorizontalScrollBarVisibility="Auto"
DoubleTapped="ScrollViewer_DoubleTapped">
<!-- SpacoContentsView1は、このPageの名前です。 -->
<Image HorizontalAlignment="Center" VerticalAlignment="Center"
Source="{Binding MediaCache}"
MaxWidth="{Binding DataContext.ContentWidth, ElementName=SpacoContentsView1}"
MaxHeight="{Binding DataContext.ContentHeight, ElementName=SpacoContentsView1}"/>
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
// spacomicComicViewModelは、SpacomicComicViewModelのインスタンスです。
// FlipViewのサイズが変化した時に実行します。
private void FlipView_SizeChanged( object sender, SizeChangedEventArgs e ) {
spacomicComicViewModel.ContentWidth = e.NewSize.Width;
spacomicComicViewModel.ContentHeight = e.NewSize.Height;
}
Igor Ralicさん、ありがとうございました!
なお、3.はScrollViewerのDoubleTappedイベントで、ZoomFactorの値が1.0が1.0より大きいかを判別し、拡大・縮小処理を行うようにしました。
5. おわりに
今回は、すぱこみっく!ユニバースのリリース後記を色々と書きました。
初めてのUWPアプリ開発で、不安とワクワク感でいっぱいでしたが、実際にストアへの提出までやってみて、UWPの画面遷移やSplitView、GridView、FlipViewコントロールの使い方、パッケージ作成、ストアへの申請など、新しいことを色々学ぶことできました。
今後もUWPアプリを開発していきたいし、さらにはXamarinを使ってAndroidアプリも実際に開発してGoogle Playに公開してみたいです。
そうだ、あの時「アプリをリリースしたら、今度のプロ生勉強会でLTする」と、Twitterで宣言したのでした。
アプリを無事にストアへ公開できたら、今度のプロ生勉強会でLTしよっと
— 智中ニア(Nia Tomonaka) (@nia_tn1012) 2016年10月11日
もちろん、アプリをリリースできたので、LTしますとも! 半年ぶりに参加するプロ生勉強会が楽しみです。
それでは、See you next!
コメント