Xamarin.FormsでSnackBarを表示してみた
はじめに
今回はAndroidのSnackBarをXamarin.FormsでAndroid/iOSで実装してみました。
完成動画はこちら
— ゆ~か (@yu_ka1984) 2017年5月13日
コードはこちら
SnackBarはAndroidのマテリアルデザインライブラリに含まれる表現で、画面下からちょこっと出てきて通知を行ったりToastと違いタップによって動作を行ったりすることができます。
今回はXamairn.FormsでSnackBarをAndroid/iOSで使用してみたいと思います。
共通部分解説
まずは共通ライブラリで使用するインターフェース
public interface ISnackBar { void Show(string text, int duration, string actionText, Action action); }
本来ならもっとオプション化が必要になりますが、今回はそれは主旨ではないので省きます。
Android実装開設
XamarinForms_SnackBar/AndroidSnackBar.cs at master · yuka1984/XamarinForms_SnackBar · GitHub
AndroidはSnackBarを直接呼び出しているだけなので特に特殊なことはないです。
iOS実装開設
XamarinForms_SnackBar/TouchSnackBar.cs at master · yuka1984/XamarinForms_SnackBar · GitHub
考え方としてはUIViewでSnackBarの見た目を構築してUIView.Animateにて表示アニメーション、時間経過後およびAction実行時に閉じるアニメーションを行っています。
KeyWindowにAddSubViewしているのでXamarin.Formsで画面遷移してもSnackBarは表示されたままになります。
これを例えば表示中のViewに表示したいようなケースの場合にはwindowsのPresentatedViewControllerにAddSubViewすればよいです。
How to acces the current view UIViewController from an external service — Xamarin Forums
SnackBarのレイアウトはLaytouAnchorを使用しています。
iOS 9で追加されたNSLayoutAnchor使うと簡単にわかりやすく間違えずにNSLayoutConstraint(制約)が作れます【Auto Layout】 - Qiita
UIView.Animateでは定義したTopのLayoutAnchorに対してConstantプロパティを変更してAnimationを行っています。
UIView.Animate(OpenDuration, () => { initialTop.Constant -= BoxHeighy; window.LayoutIfNeeded(); });
AndroidのSnackBarは重ねて表示するということがなくSnackBar表示中に別のSnackBarを表示した場合には、まず現在表示中のSnackBarが閉じて新しいSnackBarが開くという動作になるため、iOSでもそのように実装しました。
_addedsnacks にUIViewと表示待機ノ為のTask.Delayに設定したCancellationTokenSourceを保持させておきShowメソッドが呼び出された際にはClearSnackにてDelayをキャンセルさせて表示中SnackBarを閉じ、その後新しいSnackBarを表示します。
private async Task ClearSnack() { var count = _addedsnacks.Count; foreach (var added in _addedsnacks) added.Item1.Cancel(); await Task.Delay((int) (CloseDuration * 1000 * count)); }
Actionの実行に関しては引数で受け取ったActionクラスを使って表示待機をキャンセル後Actionを実行しています。
button.TouchUpInside += (sender, e) => { cancel.Cancel(); action(); };
SnackBarの利用
めんどくさがってすいません。
もう少しちゃんと実装するならDependencyService使うなりContainer使うなりしてください。
public partial class SnackBarSamplePage : ContentPage { public SnackBarSamplePage() { InitializeComponent(); SnackButton.Clicked += ButtonOnClicked; #if __IOS__ snackbar = new SnackBarSample.iOS.TouchSnackBar(); #else snackbar = new SnackBarSample.Droid.AndroidSnackBar(); #endif } private ISnackBar snackbar = null; private void ButtonOnClicked(object sender, EventArgs eventArgs) { snackbar.Show("Description" + DateTime.Now.ToString(), 2500, "Click", () => { DisplayAlert("alert", "click", "close"); }); } }
おわりに
いかがでしょうか?
こんな感じで割と簡単にアニメーション付きの特殊動作などを実行することができます。
ではでは( `ー´)ノ