Facebookを真似る、展開/縮小するナビゲーションバーを表示する


128

新しいiOS7 Facebook iPhoneアプリでは、ユーザーが上にスクロールすると、navigationBar徐々に非表示になり、完全に消えます。次に、ユーザーが下にスクロールすると、navigationBar徐々に表示されます。

この動作を自分でどのように実装しますか?私は次の解決策を認識していますが、すぐに消え、ユーザーのスクロールジェスチャーの速度とはまったく関係がありません。

[navigationController setNavigationBarHidden: YES animated:YES];

「拡張/縮小」動作をどのように記述するのが最善かわからないため、これが重複していないことを願っています。


2
同じ問題: stackoverflow.com/questions/21929220/…Safariの動作と完全に一致さ せるのは非常に難しいことに注意してください。非常に複雑なルールがいくつかあります!
Fattie、2014

1
私のプロジェクトでは、このプロジェクトを使用しましたが、問題なく動作しました。そのドキュメントを見てください。
Vinicius

github.com/bryankeller/BLKFlexibleHeightBarを使用すると、必要な操作を行うことができます。最大化から最小化への移行の各段階でバーがどのように見えるかを正確に指定できます。独自の動作を指定することもできるため、Safari、Facebook、またはその他のアプリのように動作できます。
blkhp19

私はuinavigationbarを使用しませんでしたが、代わりにuiviewを追加しました。ナビゲーションバーを複製するビューは、スクロールに基づいて拡大および縮小します。タスクを達成するためにscrollViewDidScrollデリゲートメソッドを使用しました。以下のソースコードを確認して実行することをお勧めします。dropbox.com/s/b2c0zw6yvchaia5/FailedBanks.zip?dl
Deepak Thakur

回答:


162

@peerlessによって与えられる解決策は素晴らしいスタートですが、スクロールの速度を考慮せずに、ドラッグが開始されるたびにアニメーションを開始するだけです。これにより、Facebookアプリよりも途方もないエクスペリエンスが実現します。Facebookの動作と一致させるには、次のことが必要です。

  • ドラッグの速度に比例する速度でナビゲーションバーを非表示/表示します
  • バーが部分的に非表示になっているときにスクロールが停止した場合、アニメーションを開始してバーを完全に非表示にします
  • バーが縮小するにつれて、ナビゲーションバーのアイテムをフェードします。

まず、次のプロパティが必要です。

@property (nonatomic) CGFloat previousScrollViewYOffset;

そしてここにUIScrollViewDelegateメソッドがあります:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect frame = self.navigationController.navigationBar.frame;
    CGFloat size = frame.size.height - 21;
    CGFloat framePercentageHidden = ((20 - frame.origin.y) / (frame.size.height - 1));
    CGFloat scrollOffset = scrollView.contentOffset.y;
    CGFloat scrollDiff = scrollOffset - self.previousScrollViewYOffset;
    CGFloat scrollHeight = scrollView.frame.size.height;
    CGFloat scrollContentSizeHeight = scrollView.contentSize.height + scrollView.contentInset.bottom;

    if (scrollOffset <= -scrollView.contentInset.top) {
        frame.origin.y = 20;
    } else if ((scrollOffset + scrollHeight) >= scrollContentSizeHeight) {
        frame.origin.y = -size;
    } else {
        frame.origin.y = MIN(20, MAX(-size, frame.origin.y - scrollDiff));
    }

    [self.navigationController.navigationBar setFrame:frame];
    [self updateBarButtonItems:(1 - framePercentageHidden)];
    self.previousScrollViewYOffset = scrollOffset;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self stoppedScrolling];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
                  willDecelerate:(BOOL)decelerate
{
    if (!decelerate) {
        [self stoppedScrolling];
    }
}

これらのヘルパーメソッドも必要です。

- (void)stoppedScrolling
{
    CGRect frame = self.navigationController.navigationBar.frame;
    if (frame.origin.y < 20) {
        [self animateNavBarTo:-(frame.size.height - 21)];
    }
}

- (void)updateBarButtonItems:(CGFloat)alpha
{
    [self.navigationItem.leftBarButtonItems enumerateObjectsUsingBlock:^(UIBarButtonItem* item, NSUInteger i, BOOL *stop) {
        item.customView.alpha = alpha;
    }];
    [self.navigationItem.rightBarButtonItems enumerateObjectsUsingBlock:^(UIBarButtonItem* item, NSUInteger i, BOOL *stop) {
        item.customView.alpha = alpha;
    }];
    self.navigationItem.titleView.alpha = alpha;
    self.navigationController.navigationBar.tintColor = [self.navigationController.navigationBar.tintColor colorWithAlphaComponent:alpha];
}

- (void)animateNavBarTo:(CGFloat)y
{
    [UIView animateWithDuration:0.2 animations:^{
        CGRect frame = self.navigationController.navigationBar.frame;
        CGFloat alpha = (frame.origin.y >= y ? 0 : 1);
        frame.origin.y = y;
        [self.navigationController.navigationBar setFrame:frame];
        [self updateBarButtonItems:alpha];
    }];
}

少し異なる動作の場合は、スクロール時にバーを再配置する行(のelseブロックscrollViewDidScroll)を次の行に置き換えます。

frame.origin.y = MIN(20, 
                     MAX(-size, frame.origin.y - 
                               (frame.size.height * (scrollDiff / scrollHeight))));

これにより、絶対量ではなく、最後のスクロール率に基づいてバーが配置され、フェードが遅くなります。本来の振る舞いはよりFacebookに似ていますが、私もこれが好きです。

注:このソリューションはiOS 7以降のみです。古いバージョンのiOSをサポートしている場合は、必要なチェックを必ず追加してください。


これは機能します。あなたがバーボタンアイテムがカスタムビューを持っていると仮定しているのを除いて。私の場合、カスタムビューはありません。したがって、上記はバーボタンを非表示にしません。@peerlessソリューションは、ナビゲーションバーアイテムを非表示および表示するのに適していると思います
Dhanush

1
あなたが正しいです。今週末、より一般的な解決策を検討するかもしれません。の代わりにデフォルトのアイテムをターゲットにするのは難しくありませんcustomView
ウェイン

@Dhanushの問題には対処していませんが、更新はあります。
ウェイン

1
ストックバーボタンの問題を修正しましたが、このコードには別の問題があります。場合ScrollViewのは、contentSizeフレームよりも小さい場合、スライドのアニメーションは動作しません。また、ですべてのナビゲーションアイテムのアルファを1.0にリセットしてくださいviewDidDisappear
Legoless、2014年

1
AutoLayoutを使用するコントローラーでこのソリューションを確認しましたか?私の場合、
AutoLayout

52

編集:iOS 8以降のみ。

使ってみる

self.navigationController.hidesBarsOnSwipe = YES;

私のために働く。

コーディングが迅速な場合は、この方法を使用する必要があります(https://stackoverflow.com/a/27662702/2283308から)

navigationController?.hidesBarsOnSwipe = true

これは、iOS <8.0では使用できません
Petar

1
pet60t0が言ったように、そして申し訳ありませんが、iOS 8以降でのみ動作します。
PedroRomão2015年

4
その後、どのように持ち帰りますか?
C0D3 2015

それは少し奇妙な動作です。私はあまり探索しませんでしたが、より速くスクロールすると再び表示されます。
PedroRomão2015

@PedroRomão素晴らしい答え。
Gagan_iOS

43

これがもう1つの実装です:TLYShyNavBar v1.0.0がリリースされました!

私は提供されたソリューションを試して自分で作成することにしました。私には、パフォーマンスが悪かったか、エントリとボイラープレートコードの障壁が高かったか、またはナビゲーションバーの下の拡張ビューが欠けていました。このコンポーネントを使用するには、次のことを行うだけです。

self.shyNavBarManager.scrollView = self.scrollView;

ああ、それは私たち自身のアプリでテストされた戦いです。


@TimArnoldご意見ありがとうございます!私はその問題を修正しました、まだポッドを更新していません> _ <は今それを行います!..ポッドが更新されました!
Mazyod 2014

もう一発!ありがとう!
Tim Camber、2014

私はあなたの助けに感謝します。あなたのコミットが助けたようです。私のUICollectionViewがナビゲーションバーのように適切にサイズ変更されないという奇妙な問題がまだあります。そのため、ナビゲーションバーが使用される場所にあるセルは、コレクションビューの境界の外にあるためクリップされます。なぜこれが起こっているのか知っていますか?
Tim Camber、2014

4
図:このコメントを書いてから数秒後に私の解決策が見つかりました。にextendedLayoutIncludesOpaqueBars設定さYESれていることを確認しなければなりませんでしたUICollectionViewController
Tim Camber 14

@TimArnoldそれはすごい!同じ問題を抱えている別の男がました。うまくいけば、あなたの解決策が彼を助けるでしょう。
Mazyod 2014

33

あなたは私を見て持つことができGTScrollNavigationBarを。UIScrollViewのスクロールに基づいてスクロールするように、UINavigationBarをサブクラス化しました。

注:OPAQUEナビゲーションバーを使用している場合、ナビゲーションバーが非表示になるため、スクロールビューを拡張する必要があります。これはまさにGTScrollNavigationBarが行うことです。(iOSのSafariなどと同じです)。


ところで、読む人のための、正確にinitWithNavigationBarClassを呼び出す方法... stackoverflow.com/questions/22286166
Fattie

@Thuy素晴らしい仕事人!だから私はこれをテーブルビューコントローラーで完全に機能させています... 1つだけ例外があります... プルダウンして更新しようとすると、奇妙になります。これには回避策がありますか?
aherrick 2014年

@Thuyも...下部にテーブルビューを実装したビューコントローラーがあったとしましょう。機能するテーブルビューに接続したいのですが、テーブルビューの上にある別のビューも非表示にしたいです。これはどのように機能しますか?
aherrick 2014年

25

iOS8には、ナビゲーションバーを非表示にするプロパティが含まれています。それを示すWWDCビデオがあります。「iOS 8のView Controller Advancements」を検索してください。

class QuotesTableViewController: UITableViewController {

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    navigationController?.hidesBarsOnSwipe = true
}

}

その他の特性:

class UINavigationController : UIViewController {

    //... truncated

    /// When the keyboard appears, the navigation controller's navigationBar toolbar will be hidden. The bars will remain hidden when the keyboard dismisses, but a tap in the content area will show them.
    @availability(iOS, introduced=8.0)
    var hidesBarsWhenKeyboardAppears: Bool
    /// When the user swipes, the navigation controller's navigationBar & toolbar will be hidden (on a swipe up) or shown (on a swipe down). The toolbar only participates if it has items.
    @availability(iOS, introduced=8.0)
    var hidesBarsOnSwipe: Bool
    /// The gesture recognizer that triggers if the bars will hide or show due to a swipe. Do not change the delegate or attempt to replace this gesture by overriding this method.
    @availability(iOS, introduced=8.0)
    var barHideOnSwipeGestureRecognizer: UIPanGestureRecognizer { get }
    /// When the UINavigationController's vertical size class is compact, hide the UINavigationBar and UIToolbar. Unhandled taps in the regions that would normally be occupied by these bars will reveal the bars.
    @availability(iOS, introduced=8.0)
    var hidesBarsWhenVerticallyCompact: Bool
    /// When the user taps, the navigation controller's navigationBar & toolbar will be hidden or shown, depending on the hidden state of the navigationBar. The toolbar will only be shown if it has items to display.
    @availability(iOS, introduced=8.0)
    var hidesBarsOnTap: Bool
    /// The gesture recognizer used to recognize if the bars will hide or show due to a tap in content. Do not change the delegate or attempt to replace this gesture by overriding this method.
    @availability(iOS, introduced=8.0)
    unowned(unsafe) var barHideOnTapGestureRecognizer: UITapGestureRecognizer { get }
}

http://natashatherobot.com/navigation-bar-interactions-ios8/で見つかります


12

私はそのためのある種の迅速で汚い解決策を持っています。詳細なテストは行っていませんが、アイデアは次のとおりです。

そのプロパティは、UITableViewControllerクラスのすべての項目をナビゲーションバーに保持します。

@property (strong, nonatomic) NSArray *navBarItems;

同じUITableViewControllerクラスで:

-(void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
    if([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f){
        return;
    }

    CGRect frame = self.navigationController.navigationBar.frame;
    frame.origin.y = 20;

    if(self.navBarItems.count > 0){
        [self.navigationController.navigationBar setItems:self.navBarItems];
    }

    [self.navigationController.navigationBar setFrame:frame];
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f){
        return;
    }

    CGRect frame = self.navigationController.navigationBar.frame;
    CGFloat size = frame.size.height - 21;

    if([scrollView.panGestureRecognizer translationInView:self.view].y < 0)
    {
        frame.origin.y = -size;

        if(self.navigationController.navigationBar.items.count > 0){
            self.navBarItems = [self.navigationController.navigationBar.items copy];
            [self.navigationController.navigationBar setItems:nil];
        }
    }
    else if([scrollView.panGestureRecognizer translationInView:self.view].y > 0)
    {
        frame.origin.y = 20;

        if(self.navBarItems.count > 0){
            [self.navigationController.navigationBar setItems:self.navBarItems];
        }
    }

    [UIView beginAnimations:@"toggleNavBar" context:nil];
    [UIView setAnimationDuration:0.2];
    [self.navigationController.navigationBar setFrame:frame];
    [UIView commitAnimations];
}

これはios> = 7の場合のみです。醜いのはわかっていますが、これをすばやく実現する方法です。コメント/提案は大歓迎です:)


12

これはiOS 8以降で機能し、ステータスバーが背景を保持することを保証します

self.navigationController.hidesBarsOnSwipe = YES;
CGRect statuBarFrame = [UIApplication sharedApplication].statusBarFrame;
UIView *statusbarBg = [[UIView alloc] initWithFrame:statuBarFrame];
statusbarBg.backgroundColor = [UIColor blackColor];
[self.navigationController.view addSubview:statusbarBg];

ステータスバーをタップしたときにナビゲーションバーを表示したい場合は、次のようにします。

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
     self.navigationController.navigationBarHidden = NO;
}

10

これが私の実装です:SherginScrollableNavigationBar

私のアプローチでは、の状態KVOを監視するUIScrollViewために使用しているため、デリゲートを使用する必要はありません(このデリゲートを他の必要なものに使用できます)。


参考までに、これは常に正しく機能するとは限りません。私もこれを試しましたが、スクロールビューを「バウンス」させない限り機能します。バウンス部分ではKVOがトリガーされないようです。ただし、contentOffsetのデリゲート呼び出しがトリガーされます。
Joris Mans

7

私のこの解決策を試してみて、なぜこれが以前の答えほど良くないのか教えてください。

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    if (fabs(velocity.y) > 1)
        [self hideTopBar:(velocity.y > 0)];
}

- (void)hideTopBar:(BOOL)hide
{
    [self.navigationController setNavigationBarHidden:hide animated:YES];
    [[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide];
}

1
私はこれに似た何かをしました、そしてこれは簡単に最良の解決策です。私はいくつかのハックとライブラリを試しましたが、これはiOS 9で機能し、画面全体をカバーしないtableViewで動作する唯一のものです。賞賛!
skensell 2016

6

これを達成した1つの方法は次のとおりです。

であるためにあなたのビューコントローラを登録しUIScrollViewDelegate、あなたのUITableView例のために。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

UIScrollViewDelegateメソッド内から、新しいcontentOffsetを取得して、UINavigationBarそれに応じアップまたはダウン。

サブビューのアルファの設定は、設定および計算できるいくつかのしきい値と係数に基づいて行うこともできます。

それが役に立てば幸い!



ダイアナさん、ありがとう!UIScrollViewDelegateメソッドを実装する必要があるのではないかと思いましたが、少々やり過ぎかもしれません。このことがわかったら、投稿します。乾杯!
El Mocoso 2013年

4

Iwburkの回答に加えて、非カスタムナビゲーションバーのアルファの問題を修正し、viewWillDisappearメソッドでナビゲーションバーをリセットするために、次を追加しました。

- (void)updateBarButtonItems:(CGFloat)alpha
{
    for (UIView *view in self.navigationController.navigationBar.subviews) {
        NSString *className = NSStringFromClass([view class]);

        if ( ![className isEqualToString:@"_UINavigationBarBackground"] ) {
            view.alpha = alpha;
        }
    }
}

- (void)resetNavigationBar {
    CGRect frame = self.navigationController.navigationBar.frame;
    frame.origin.y = 20;
    [self.navigationController.navigationBar setFrame:frame];
    [self updateBarButtonItems:1.0f];
}

サブビューをループする以外の方法はありますか?
thisiscrazy4 14年

非カスタムナビゲーションバーでわかることから、合計4つのサブビューがあります:_UINavigationBarBackground、UINavigationItemView、UINavigationItemButtonView、および_UINavigationBarBackIndicatorView。ループはかなり高速で、アプリのパフォーマンスに影響を与えていないようです。
blueice 2014年

_UINavigationBarBackgroundは常に最初のサブビューのように見えるので、残りの部分に直接アクセスできます:((UIView *)self.navigationController.navigationBar.subviews [1])。alpha = alpha;
blueice 2014年

4

私はあらゆるスタイルとあらゆる振る舞いを可能にするソリューションを探していました。多くの異なるアプリでは、バーの凝縮動作が異なることに気づくでしょう。そしてもちろん、バーの見え方はアプリによってまったく異なります。

この問題の解決策をhttps://github.com/bryankeller/BLKFlexibleHeightBar/で作成しました

独自の動作ルールを定義して、バーが縮小および拡大する方法とタイミングを制御できます。また、バーのサブビューがバーの凝縮または拡大にどのように反応するかを正確に定義できます。

どんな種類のヘッダーバーも考えられるように多くの柔軟性が必要な場合は、私のプロジェクトをご覧ください。


上にスクロールすると非表示になるボタンをこのcustomHeaderViewに追加するにはどうすればよいですか?静的なボタンは必要ありません。それは可能ですか?サブビューとして1つのボタンを作成しようとしましたが、タッチされていません。
abhimuralidharan 2016年

3

UITableViewについてカスタマイズされたヘッダーが必要な状況で、この動作をエミュレートしようとしていました。独自の「ナビゲーション」バーをロールバックしました。これは、ページ上の他の多くのものの下にあり、セクションヘッダーがデフォルトの「ドッキング」動作に従うようにしたためです。Facebook / Instagram / Chrome /などで見られるのと同じようなスタイルで、UITableView / UIScrollViewを別のオブジェクトと一緒に調整するためのかなり巧妙で簡潔な方法を見つけたと思います。アプリ。

私の.xibファイルで、コンポーネントをフリーフォームビューにロードしています:http ://imgur.com/0z9yebJ(申し訳ありませんが、インライン画像への担当者がいません)

左側のサイドバーでは、テーブルがメインヘッダービューの後ろに並べられていることに注意してください。スクリーンショットからはわかりませんが、メインヘッダービューと同じy位置にあります。これは見えないところまで伸びているため、UITableViewのcontentInsetプロパティは76(メインヘッダービューの高さ)に設定されています。

メインヘッダービューをUIScrollViewと一斉にスライドさせるには、UIScrollViewDelegateのscrollViewDidScrollメソッドを使用していくつかの計算を実行し、UIScrollViewのcontentInsetとメインヘッダービューのフレームを変更します。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    UIEdgeInsets insets = scrollView.contentInset;
    //tableViewInsetDelta and tableViewOriginalInsetValue are NSInteger variables that I set to 0 and 76, respectively, in viewDidLoad
    tableViewInsetDelta = tableViewOriginalInsetValue + scrollView.contentOffset.y;
    insets.top = tableViewOriginalInsetValue - tableViewInsetDelta;

    if (scrollView.contentOffset.y > -76 && scrollView.contentOffset.y < 0) {
        [scrollView setContentInset:insets];
        self.pathTitleContainer.frame = CGRectMake(self.pathTitleContainer.frame.origin.x, 44 - tableViewInsetDelta, self.pathTitleContainer.frame.size.width, self.pathTitleContainer.frame.size.height);
    } else if (scrollView.contentOffset.y > 0) {
        insets.top = 0;
        [scrollView setContentInset:insets];
        self.pathTitleContainer.frame = CGRectMake(self.pathTitleContainer.frame.origin.x, -32, self.pathTitleContainer.frame.size.width, self.pathTitleContainer.frame.size.height);
    } else if (scrollView.contentOffset.y < -76) {
        insets.top = 76;
        [scrollView setContentInset:insets];
        self.pathTitleContainer.frame = CGRectMake(self.pathTitleContainer.frame.origin.x, 44, self.pathTitleContainer.frame.size.width, self.pathTitleContainer.frame.size.height);
    }
}

最初のifステートメントは重い作業のほとんどを行いますが、ユーザーが強制的にドラッグしていて、scrollViewDidScrollに送信された最初のcontentOffset値が最初のifの範囲外である場合に対処するために、他の2つを含める必要がありました。ステートメントの。

最終的に、これは私にとって本当にうまく機能しています。プロジェクトを大量の肥大したサブクラスでロードするのは嫌いです。これがパフォーマンスの面で最高のソリューションであるかどうかはわかりません(コードが常に呼び出されるため、scrollViewDidScrollにコードを配置することは常にためらっていました)が、コードフットプリントは、これまでで最も小さいこの問題の解決策であり、UIScrollViewにUITableViewをネストする必要はありません(Appleはドキュメントでこれを推奨しておらず、タッチイベントはUITableViewで少しファンキーになります)。これが誰かを助けることを願っています!



2

GTScrollNavigationBarを実装してみましたが、私のアプリでは自動レイアウト制約を変更する必要がありました。他の誰かが自動レイアウトでこれを行う必要がある場合に備えて、私の実装の例をGitHubに公開することにしました。他のほとんどの実装で私が抱えていたもう1つの問題は、スクロールとスクロールビューのサイズを同時に調整するときに作成する視差スクロール効果を回避するために、人々がスクロールビューの境界を設定しないことです。

自動レイアウトでこれを行う必要がある場合は、JSCollapsingNavBarViewControllerを確認してください。2つのバージョンを含めました。1つはナビゲーションバーのみで、もう1つはナビゲーションバーの下にサブバーがあり、ナビゲーションバーを折りたたむ前に折りたたまれています。


1

私はこの方法でそれを試しました、それが役に立てば幸いです。デリゲートメソッドでコードを実装し、目的のビュー/サブビューに設定するだけです

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
            CGRect frame=self.view.frame;
            CGRect resultFrame=CGRectZero;
            if(scrollView.contentOffset.y==0 || scrollView.contentOffset.y<0){
                self.lastContentOffset=0;
                self.offset=0;
                resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                [self showHide:YES withFrame:resultFrame];
            }else if (self.lastContentOffset > scrollView.contentOffset.y){
                NSNumber *temp=[NSNumber numberWithDouble:self.lastContentOffset-scrollView.contentOffset.y];
                if(temp.intValue>40 || self.offset.intValue<temp.intValue){
                    self.offset=[NSNumber numberWithInt:0];
                    resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                    [self showHide:YES withFrame:resultFrame];
                }else{
                    if(temp.intValue>0){
                        self.offset=[NSNumber numberWithInt:self.offset.intValue-temp.intValue];
                        resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                        [self showHide:YES withFrame:resultFrame];
                    }
                }
            }else if (self.lastContentOffset < scrollView.contentOffset.y){
                NSNumber *temp=[NSNumber numberWithDouble:scrollView.contentOffset.y-self.lastContentOffset];
                if(self.offset.intValue>40 || (self.offset.intValue+temp.intValue)>40){
                    self.offset=[NSNumber numberWithInt:40];
    // Pass the resultFrame
                    [self showHide:NO withFrame:resultFrame];
                }else{
                    self.offset=[NSNumber numberWithInt:self.offset.intValue+temp.intValue];
                    resultFrame=CGRectMake(0, frame.size.height-(40-self.offset.intValue), frame.size.width, 40-self.offset.intValue);
    // Pass the resultFrame
                    [self showHide:YES withFrame:resultFrame];
                }
            }
            self.lastContentOffset = scrollView.contentOffset.y;

        }

-(void)showHide:(Boolean)boolView withFrame:(CGRect)frame{
               if(showSRPFilter){
                        //Assign value of "frame"to any view on which you wan to to perform animation
                }else{
                       //Assign value of "frame"to any view on which you wan to to perform animation
                }
        }

1

@Iwburkの答えの拡張...ナビゲーションバーの原点を変更する代わりに、ナビゲーションバーのサイズを拡大/縮小する必要がありました。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect frame = self.previousRect; // a property set in the init method to hold the initial size of the uinavigationbar
    CGFloat size = frame.size.height;
    CGFloat framePercentageHidden = ((MINIMUMNAVBARHEIGHT - frame.origin.y) / (frame.size.height - 1));
    CGFloat scrollOffset = scrollView.contentOffset.y;
    CGFloat scrollDiff = scrollOffset - self.previousScrollViewYOffset;
    CGFloat scrollHeight = scrollView.frame.size.height;
    CGFloat scrollContentSizeHeight = scrollView.contentSize.height + scrollView.contentInset.bottom;

    if (scrollOffset <= -scrollView.contentInset.top) {
        frame.origin.y = -MINIMUMNAVBARHEIGHT;
    } else if ((scrollOffset + scrollHeight) >= scrollContentSizeHeight) {
        frame.origin.y = -size;
    } else {
        frame.origin.y = MIN(-MINIMUMNAVBARHEIGHT, MAX(-size, frame.origin.y - scrollDiff));
    }

    self.previousRect = CGRectMake(0, frame.origin.y, self.jsExtendedBarView.frame.size.width, 155);
    self.layoutConstraintExtendedViewHeight.constant = MAXIMUMNAVBARHEIGHT + frame.origin.y + MINIMUMNAVBARHEIGHT;
    [self updateBarButtonItems:(1 - framePercentageHidden)];
    self.previousScrollViewYOffset = scrollOffset;
}

それはstoppedScrollingまだメソッドで動作しません、私がそれを持っているときに間違ってアップデートを投稿します


0

これらのアプローチはすべて非常に複雑に見えます...だから当然、私は自分で作成しました:

class ViewController: UIViewController, UIScrollViewDelegate {
    var originalNavbarHeight:CGFloat = 0.0
    var minimumNavbarHeight:CGFloat = 0
    weak var scrollView:UIScrollView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // setup delegates 
        scrollView.delegate = self
        // save the original nav bar height
        originalNavbarHeight = navigationController!.navigationBar.height
    }


    func scrollViewDidScroll(scrollView: UIScrollView) {
        // will relayout subviews
        view.setNeedsLayout() // calls viewDidLayoutSubviews
    }

    override func viewDidLayoutSubviews() {
        var percentageScrolled = min(scrollView.contentOffset.y / originalNavbarHeight, 1)
        navigationController?.navigationBar.height = min(max((1 - percentageScrolled) * originalNavbarHeight, minimumNavbarHeight), originalNavbarHeight)
        // re-position and scale scrollview
        scrollView.y = navigationController!.navigationBar.height + UIApplication.sharedApplication().statusBarFrame.height
        scrollView.height = view.height - scrollView.y
    }

    override func viewWillDisappear(animated: Bool) {
        navigationController?.navigationBar.height = originalNavbarHeight
    }

}

navigationBar.height?scrollView.height?frameプロパティの拡張機能を使用していますか?
エリー

0

Objective-Cで示されたすべての回答が見つかりました。これはSwift 3での私の答えです。これは非常に一般的なコードであり、直接使用できます。UIScrollViewとUITableViewの両方で動作します。

var lastContentOffset: CGPoint? = nil
var maxMinus: CGFloat           = -24.0
var maxPlus: CGFloat            = 20.0
var initial: CGFloat            = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    self.title = "Alarm Details"
    self.lastContentOffset = self.alarmDetailsTableView.contentOffset
    initial = maxPlus
}

func scrollViewDidScroll(_ scrollView: UIScrollView)
{
    var navigationBarFrame: CGRect   = self.navigationController!.navigationBar.frame
    let currentOffset = scrollView.contentOffset

    if (currentOffset.y > (self.lastContentOffset?.y)!) {
        if currentOffset.y > 0 {
            initial = initial - fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
        else if scrollView.contentSize.height < scrollView.frame.size.height {
            initial = initial + fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
    }
    else {
        if currentOffset.y < scrollView.contentSize.height - scrollView.frame.size.height {
            initial = initial + fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
        else if scrollView.contentSize.height < scrollView.frame.size.height && initial < maxPlus {
            initial = initial - fabs(CGFloat(currentOffset.y - self.lastContentOffset!.y))
        }
    }

    initial = (initial <= maxMinus) ? maxMinus : initial
    initial = (initial >= maxPlus) ? maxPlus : initial

    navigationBarFrame.origin.y = initial

    self.navigationController!.navigationBar.frame = navigationBarFrame
    scrollView.frame = CGRect(x: 0.0, y: initial + navigationBarFrame.size.height , width: navigationBarFrame.size.width, height: self.view.frame.size.height - (initial + navigationBarFrame.size.height))

    let framePercentageHidden: CGFloat              = ((20 - navigationBarFrame.origin.y) / (navigationBarFrame.size.height));
    self.lastContentOffset                          = currentOffset;
    self.updateBarButtonItems(alpha: 1 - framePercentageHidden)
}

func updateBarButtonItems(alpha: CGFloat)
{
    self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.darkGray.withAlphaComponent(alpha)]
    self.navigationController?.navigationBar.isUserInteractionEnabled = (alpha < 1) ? false: true

    guard (self.navigationItem.leftBarButtonItems?.count) != nil else { return }

    for (_, value) in self.navigationItem.leftBarButtonItems!.enumerated() {
        value.customView?.alpha = alpha
    }

    guard (self.navigationItem.rightBarButtonItems?.count) != nil else { return }

    for (_, value) in (self.navigationItem.rightBarButtonItems?.enumerated())! {
        value.customView?.alpha = alpha
    }
}

アルファをナビゲーション項目に設定するロジックは@からコピーされます WayneBurkettの回答れ、Swift 3で書き直されました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.