メニューを閉じる

テクノデジタルグループ

メニューを開く

2014.06.19

プログラミング

自作のツールバーがiOSのSafariっぽく動くようにする

こんにちは、ZYです。

今回は、

「その動き、君がいいねと言ったら、Safari記念日」

ということで、「なんかiOSのSafariっぽい挙動をする自作ツールバー」を紹介します。

と、いっても、今回再現するのは、「スクロール時やタップ時に、ツールバーが出たり引っ込んだりする動き」です。中のボタンの動きなんかは再現しないので、あしからず。

 

さて。まずは、iOSのSafariで使われているToolBarの挙動を確認しておきましょう。

 

出てくるイベント

1.勢いよく上にスクロール(指は下にpan)した時

(ゆっくりした時は、出てこない)

2.一番下までスクロールした時

3.画面下部をタップした時

 

隠れるイベント

4.下にスクロールした時

(スクロールにあわせて、途中までゆっくり降りて、ある程度まで行くとアニメーションで隠れる)

 

以上の動作を、各イベントにあわせて自作のツールバーが動くように実装していきます。

 

以下が、そのコードです。

 

@interface ImitateSafariToolBarViewController : UIViewController<UIScrollViewDelegate>
// スクロールビュー 
@property  UIScrollView *scrollView;
// 自作ツールバー 縦幅44
@property  UIView *toolBar;

// 制御用の変数たち。
@property BOOL showReplyView;
@property BOOL animetionReplyView;

@end

 

 

// 自作ツールバーを動かすイベントを取るUIScrollViewデリゲート群。

// スクロールが始まった時に呼ばれるメソッド
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    // 今回は特に何もなし。
}

// スクロール中に呼ばれる
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // velocityInViewは、panの「速さ」を取得します
    CGPoint v = [scrollView.panGestureRecognizer velocityInView:scrollView];

    if(v.y > 800){
        // 勢いよく上にスクロールした場合。800は、割と反応しやすい方。
        // SafariのToolBarに近づけるなら、1100以上でもいいかも?
        [self showToolBar];
    }

    // translationInViewは、pan開始時から現在地までの「距離」を取得
    CGPoint p = [scrollView.panGestureRecognizer translationInView:scrollView];

    if(p.y <= -1){

        if (_animetionReplyView) return;
        if (! _showReplyView)  return;

        // 上にスクロールした場合
        // パンの動きに連動して、閉じる方向に少しずつ動く
        CGRect frame = self.toolBar.frame;
        frame.origin.y = self.view.frame.size.height - self.toolBar.frame.size.height + (p.y * -1);
        self.toolBar.frame = frame;

        // 一定の位置まで行くと閉じる。
        if (p.y < -22) {
            [self hideToolBar];
        }

    }


}

// ドラッグが終了した時に呼ばれる
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    // 一番下まで行くと、ツールバーを出す。
    if (scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.frame.size.height) {
        [self showToolBar];
    }

    // ツールバーがゆっくり下がっている途中で離した際には、ちょっとずれてるので、戻す
    if (_showReplyView && !_animetionReplyView) {

        if (self.toolBar.frame.origin.y != self.view.frame.size.height - self.toolBar.frame.size.height) {
            _showReplyView = NO;
            [self showToolBar];
        }
    }


}

// 慣性で動くスクロールが静止したときに呼ばれる。基本的にはドラッグを離した時と同じような動作。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    // 一番下ならツールバーを出す
    if (scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.frame.size.height) {
        _showReplyView = NO;
        [self showToolBar];
    }

    if (_showReplyView && !_animetionReplyView) {

        if (self.toolBar.frame.origin.y != self.view.frame.size.height - self.toolBar.frame.size.height) {
            [self showToolBar];
        }
    }

}


// 自作ツールバーの閉じたり出たりのアニメーション。

-(void)showToolBar{
    // ツールバーを出す
    // アニメーションの途中や、もうすでに開いてる時は動作しない。

    //if (_animetionReplyView)  return;
    if (_showReplyView)  return;

    _animetionReplyView = YES;
    CGRect frame = self.toolBar.frame;
    frame.origin.y = self.view.frame.size.height - self.toolBar.frame.size.height;

    [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{

        self.toolBar.frame = frame;


    } completion:^(BOOL finished){
        _animetionReplyView = NO;
        _showReplyView = YES;
    }];
}
-(void)hideToolBar{
     // ツールバーを隠す

    NSLog(@"end");
    //if (_animetionReplyView)  return;
    if (!_showReplyView) return;

    _animetionReplyView = YES;

    [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{
        CGRect frame = self.toolBar.frame;
        frame.origin.y = self.view.frame.size.height;
        self.toolBar.frame = frame;


    } completion:^(BOOL finished){
        _animetionReplyView = NO;
        _showReplyView = NO;
    }];
}

 

UIScrollViewのデリゲートメソッドを使っているので、UIScrollViewもしくは、その継承Class(UITableViewとか、UITextViewとか)が存在しているUIViewControllerでお使いください。

UITableViewでも、<UITableViewDelegate>を指定してやれば、ついでにUIScrollViewDelegateが呼び出されます。

 

今回は自作のツールバーを使いましたが、UINavigationControllerのtoolBarを使うことも可能。

上記のself.toolBarを、self.navigationController.toolbarに変えれば、基本的にはOK。

ふつーにself.navigationController.toolbar.frameをいじれば、動きます。

一応、

-(void)showToolBar;
-(void)hideToolBar;

を呼び出しているところを

[self.navigationController setToolbarHidden:YES animated:YES];
[self.navigationController setToolbarHidden:NO animated:YES];

に変えても動きますが・・・私がやった時は、たまにエラー落ちしてたので、あんまりおすすめしないです。

ま、でも、たぶん、ある程度条件つけて、呼び出すタイミングを制御してやれば、大丈夫ですよ、たぶん。

その他、一番下までスクロールしなくても出るようにするなど、カスタムしてお使いください。

 


【記事への感想募集中!】

記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!
  • こんな記事が読んでみたい、こんなことが知りたい、調べてほしい!という意見も募集中!
  • いただいた感想は今後の記事に活かしたいと思います!

感想フォームはこちら


【テクノデジタルではエンジニア/デザイナーを積極採用中です!】

下記項目に1つでも当てはまる方は是非、詳細ページへ!
  • 自分でアプリを作ってみたい
  • ITで世の中にワクワクを生み出したい
  • 使いやすさ、デザインにこだわったWebサイトを開発したい

採用情報の詳細はこちら


Qangaroo(カンガルー)

  • 徹底した見やすさと優れた操作性で、テストの「見える化」を実現。
  • テストの進捗が見える。開発がスマートに進む。
  • クラウド型テスト管理ツール『Qangaroo(カンガルー)』

【テクノデジタルのインフラサービス】

当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。

https://www.tcdigital.jp/infrastructure/

最近の記事