Pull up to Close を実装してみる、Xamarin.iOS で
イマドキのスマホアプリでは Pull to Refresh(引っ張って更新)を実装してるアプリをよく目にするのですが、RSS Reader の Feedly では Pull up to Close(上に引っぱって閉じる)も採用しています。
この操作性がなかなか使いやすかったので、自分でも実装してみました。
デモ #
こんな感じ。
WebView なんですが、一番下までスクロールして、さらに上に引っ張ると "Pull up to Close" → "Release to Close" とラベルが変わり、そこで離すとコールバックします。
実装してみたコード #
Xamarin.iOS ですから、C# です。
UIWebView でやってますが、ScrollView なコントロールならだいたい同じ感じでいけるんじゃないかと思います。
public partial class PullUpToCloseSampleViewController : UIViewController
{
public PullUpToCloseSampleViewController() : base ("PullUpToCloseSampleViewController", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// WebView が持ってる ScrollView、よく使うので変数化しておく
// webView は Interface Builder で UIWebView を Outlet にしたもの。
var scrollView = webView.ScrollView;
// Bounces の影を消す via http://stackoverflow.com/questions/8480571/removing-shadows-from-uiwebview
scrollView.Subviews.Where(v => v is UIImageView)
.ToList().ForEach(v => v.Hidden = true);
// 上に引っ張った時に見える背景とラベル
var bounceBackground = new UIView(
new RectangleF(0f, 0f, webView.Frame.Width, webView.Frame.Height));
bounceBackground.BackgroundColor = UIColor.LightGray;
var bounceLabel = new UILabel(
new RectangleF(0f, webView.Frame.Height - 30f, webView.Frame.Width, 30f));
bounceLabel.Text = "Pull up to Close";
bounceLabel.TextAlignment = UITextAlignment.Center;
bounceLabel.BackgroundColor = UIColor.Clear;
bounceLabel.Opaque = false;
// 背景とラベルを WebView の一番奥に追加する
webView.InsertSubview(bounceLabel, 0);
webView.InsertSubview(bounceBackground, 0);
// 適当な URL を読み込み
webView.LoadRequest(NSUrlRequest.FromUrl(new NSUrl("http://yahoo.co.jp/")));
// 閉じるのに必要な分だけ上に引っ張ったら true になる
var canClose = false;
// ドラッグ開始時にフラグOFF(一応)
scrollView.DraggingStarted += (sender, e) =>
{
canClose = false;
};
// ドラッグ終了時、必要量引っ張っていたら OnCloseByPullUp を呼ぶ
scrollView.DraggingEnded += (sender, e) =>
{
if (canClose)
{
OnCloseByPullUp();
}
};
// スクロールした時にいろいろやる
scrollView.Scrolled += (sender, e) =>
{
var labelFrame = bounceLabel.Frame;
// コンテンツの一番下まで表示してさらに引っ張ったサイズ
var offsetY = (scrollView.Frame.Height + scrollView.ContentOffset.Y)
- scrollView.ContentSize.Height;
// 50px 上に引っ張ったら閉じるものとする
canClose = offsetY > 50f;
bounceLabel.Text = canClose ? "Release to Close" : "Pull up to Close";
// ラベルがいつまでも移動しないように
if (offsetY > labelFrame.Height)
{
offsetY = labelFrame.Height;
}
// ラベルがドラッグと共に下からせり出してくるように
labelFrame.Y = scrollView.Frame.Height - offsetY;
bounceLabel.Frame = labelFrame;
};
}
// "Release to Close" で離すと呼ばれる
void OnCloseByPullUp()
{
var v = new UIAlertView("", "Close this view", null, "Close");
v.Show ();
}
}
やってる事 #
- ScrollView の「引っ張った時に見える場所(= Bounce というらしい)」の影を消す。 via http://stackoverflow.com/questions/8480571/removing-shadows-from-uiwebview
- 背景と、ラベルを WebView 内の一番奥に挿入する(引っ張った時にのみ見えるように)
- あとはイベントハンドラでの処理。スクロール中に、「最下部で引っ張り中」だったら "Pull up to Close" ラベルをアニメーションさせながら表示する。50px 以上引っ張ってたら "Release to Close" にラベルを変える。「閉じられるよ」フラグも ON にしとく。
- ドラッグ終了イベントで、「閉じられるよ」フラグが立ってたら、コールバックする。
今後 #
もうちょっとライブラリっぽくしたいですね。あと引っ張り中にアイコンとか表示させたい。
published at tags: Xamarin iOS C#- Next: Xamarin Studio で複数のソリューションを開く方法
- Previous: Xamarin Studio でコードテンプレートを使う