wake-up-neo.com

Imitieren Sie Facebook ein-/ausblenden/Erweitern/Verkleinern der Navigationsleiste

In der neuen iPhone-App für iOS7 von Facebook versteckt sich navigationBar allmählich bis zu einem Punkt, an dem der Benutzer vollständig verschwindet. Wenn der Benutzer nach unten blättert, zeigt sich navigationBar allmählich. 

Wie würden Sie dieses Verhalten selbst umsetzen? Die folgende Lösung ist mir bekannt, sie verschwindet jedoch sofort und ist nicht an die Geschwindigkeit der Bildlaufbewegung des Benutzers gebunden. 

[navigationController setNavigationBarHidden: YES animated:YES];

Ich hoffe, dass es sich dabei nicht um ein Duplikat handelt, da ich nicht sicher bin, wie ich das "Expanding/Contracting" -Verhalten am besten beschreiben kann.

125
El Mocoso

Die von @peerless gegebene Lösung ist ein großartiger Anfang, aber sie beginnt nur mit einer Animation, wenn das Ziehen beginnt, ohne die Geschwindigkeit des Bildlaufs zu berücksichtigen. Dies führt zu einem abgehackten Erlebnis, als Sie in der Facebook-App erhalten. Um dem Verhalten von Facebook zu entsprechen, müssen wir:

  • verbergen/Anzeigen der Navigationsleiste mit einer Geschwindigkeit, die der Geschwindigkeit des Ziehens proportional ist 
  • starten Sie eine Animation, um die Leiste vollständig auszublenden, wenn der Bildlauf angehalten wird, wenn die Leiste teilweise ausgeblendet ist
  • verblassen Sie die Elemente der Navbar, während die Leiste schrumpft.

Zunächst benötigen Sie folgende Eigenschaft:

@property (nonatomic) CGFloat previousScrollViewYOffset;

Und hier sind die UIScrollViewDelegate-Methoden:

- (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];
    }
}

Sie benötigen auch diese Hilfsmethoden:

- (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];
    }];
}

Für ein etwas anderes Verhalten ersetzen Sie die Zeile, in der der Balken beim Scrollen (der else-Block in scrollViewDidScroll) neu positioniert wird, durch diesen:

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

Dadurch wird der Balken basierend auf dem letzten Bildlaufprozentsatz anstelle eines absoluten Betrags positioniert, was zu einer langsameren Überblendung führt. Das ursprüngliche Verhalten ist eher Facebook-ähnlich, aber ich mag auch dieses.

Hinweis: Diese Lösung ist nur für iOS 7+ verfügbar. Fügen Sie unbedingt die erforderlichen Überprüfungen hinzu, wenn Sie ältere Versionen von iOS unterstützen.

161
Wayne Burkett

EDIT: Nur für iOS 8 und höher.

Sie können es versuchen 

self.navigationController.hidesBarsOnSwipe = YES;

Funktioniert bei mir.

Wenn Sie in Swift codieren, müssen Sie diesen Weg verwenden (von https://stackoverflow.com/a/27662702/2283308 )

navigationController?.hidesBarsOnSwipe = true
52
Pedro Romão

Hier ist eine weitere Implementierung: TLYShyNavBar v1.0.0 veröffentlicht!

Nachdem ich die angebotenen Lösungen ausprobiert hatte, entschied ich mich, meine eigenen zu machen, und für mich lief es entweder schlecht, sie hatten eine hohe Eintrittsbarriere und hatten keinen Boiler-Plattencode oder es fehlte die Erweiterungsansicht unter der Navigationsleiste. Um diese Komponente zu verwenden, müssen Sie lediglich Folgendes tun:

self.shyNavBarManager.scrollView = self.scrollView;

Oh, und es wird in unserer eigenen App getestet.

43
Mazyod

Sie können sich meine GTScrollNavigationBar ansehen. Ich habe UINavigationBar subclassed, um das Scrollen basierend auf dem Scrollen einer UIScrollView zu machen.

Hinweis: Wenn Sie eine OPAQUE-Navigationsleiste haben, muss die Bildlaufleiste ERWEITERN, da die Navigationsleiste HIDDEN wird. Genau das macht GTScrollNavigationBar. (So ​​wie zum Beispiel in Safari auf iOS.)

33
Thuy

iOS8 enthält Eigenschaften, um die Navigationsleiste kostenlos auszublenden. Es gibt ein WWDC-Video, das dies demonstriert. Suchen Sie nach "Verbesserungen für View Controller in iOS 8".

Beispiel:

class QuotesTableViewController: UITableViewController {

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

    navigationController?.hidesBarsOnSwipe = true
}

}

Andere Eigenschaften:

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 }
}

Gefunden über http://natashatherobot.com/navigation-bar-interactions-ios8/

25

Dies funktioniert für iOS 8 und höher und stellt sicher, dass die Statusleiste ihren Hintergrund behält

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

Wenn Sie die Navigationsleiste anzeigen möchten, wenn Sie auf die Statusleiste tippen, können Sie Folgendes tun:

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

Ich habe dafür eine schnelle und schmutzige Lösung. Ich habe noch keine eingehenden Tests gemacht, aber hier ist die Idee:

Diese Eigenschaft behält alle Elemente in der Navigationsleiste für meine UITableViewController-Klasse bei

@property (strong, nonatomic) NSArray *navBarItems;

In derselben UITableViewController-Klasse habe ich:

-(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];
}

Das ist nur für ios> = 7, es ist hässlich, ich weiß es, aber ein schneller Weg, um dies zu erreichen. Alle Kommentare/Vorschläge sind willkommen :)

12
peerless

Hier ist meine Implementierung: SherginScrollableNavigationBar .

In meinem Ansatz verwende ich KVO, um den Status von UIScrollView zu beobachten, so dass keine Notwendigkeit besteht, einen Delegierten zu verwenden (und Sie können diesen Delegierten für alles andere verwenden, was Sie benötigen).

10

Bitte probieren Sie diese Lösung von mir und lassen Sie mich wissen, warum dies nicht so gut ist wie die vorherigen Antworten.

- (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];
}
7
Nishant

Ich habe dies auf folgende Weise erreicht:.

Registrieren Sie Ihren View-Controller beispielsweise als UIScrollViewDelegate Ihrer UITableView.

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

Mit de UIScrollViewDelegate-Methoden können Sie das neue contentOffset abrufen und Ihre UINavigationBar entsprechend nach oben oder unten übersetzen.

Das Einstellen des Alphas der Unteransichten kann auch auf der Grundlage einiger Schwellenwerte und Faktoren erfolgen, die Sie einstellen und berechnen können.

Ich hoffe es hilft!

6
Diana Sule

Zusätzlich zu Iwburks Antwort habe ich Folgendes hinzugefügt, um das Alpha-Problem in nicht benutzerdefinierten Navigationsleisten zu beheben und die Navigationsleiste in der viewWillDisappear-Methode zurückzusetzen:

- (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];
}
4
blueice

Ich suchte nach einer Lösung, die jeden Stil und jedes Verhalten zuließ. Sie werden feststellen, dass sich das Verhalten der Balkenverdichtung in vielen verschiedenen Apps unterscheidet. Und natürlich sieht die Leiste in den Apps völlig anders aus. 

Ich habe eine Lösung für dieses Problem erstellt mit https://github.com/bryankeller/BLKFlexibleHeightBar/

Sie können Ihre eigenen Verhaltensregeln definieren, um zu steuern, wie und wann die Leiste schrumpft und wächst, und Sie können genau definieren, wie die Unteransichten der Leiste auf die Verdichtung oder das Wachstum der Leiste reagieren sollen.

Werfen Sie einen Blick auf mein Projekt, wenn Sie eine große Flexibilität wünschen, um die Kopfleiste, die Sie sich vorstellen können, zu gestalten. 

4
blkhp19

HidingNavigationBar Ein großartiges Projekt, das die Navigationsleiste und die Tab-Leiste versteckt, wenn Sie möchten.

HidingNavigationBar unterstützt das Ausblenden/Anzeigen der folgenden Ansicht Elemente:

UINavigationBar

UINavigationBar und eine Erweiterung UIView

UINavigationBar und eine UIToolbar

UINavigationBar und eine UITabBar

https://github.com/tristanhimmelman/HidingNavigationBar

3

Ich habe versucht, dieses Verhalten in einer Situation zu emulieren, in der ich einen angepassten Header über einer UITableView benötigte. Ich habe meine eigene "Navigationsleiste" gerollt, da diese unter einer Reihe anderer Elemente auf der Seite angezeigt wird und ich wollte, dass die Abschnittsheader dem Standardverhalten des "Andockens" folgen. Ich glaube, ich habe eine ziemlich clevere und prägnante Methode gefunden, um ein UITableView/UIScrollView zusammen mit einem anderen Objekt in einem Stil anzupassen, der dem von Facebook/Instagram/Chrome/etc ähnelt. Apps. 

In meiner .xib-Datei habe ich meine Komponenten in eine Freeform-Ansicht geladen: http://imgur.com/0z9yebJ (Entschuldigung, ich habe keine Vertretung für Inline-Images)

Beachten Sie, dass sich die Tabelle in der linken Seitenleiste hinter der Hauptkopfansicht befindet. Sie können den Screenshot nicht erkennen, er hat jedoch die gleiche y-Position wie die Hauptansicht des Headers. Da die contentInset-Eigenschaft in UITableView nicht angezeigt wird, ist sie auf 76 (die Höhe der Hauptheaderansicht) gesetzt.

Damit die Hauptheaderansicht im Einklang mit der UIScrollView nach oben gleitet, verwende ich die ScrollViewDidScroll-Methoden der UIScrollViewDelegate, um einige Berechnungen durchzuführen und das contentInset der UIScrollView sowie den Rahmen der Hauptheaderansicht zu ändern.

- (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);
    }
}

Die erste if -Anweisung macht den Großteil der Belastung aus, aber ich musste die anderen beiden einschließen, um Situationen zu handhaben, in denen der Benutzer gewaltsam zieht und die anfänglichen contentOffset-Werte, die an scrollViewDidScroll gesendet werden, außerhalb des Bereichs des ersten liegen. if Anweisung. 

Letztendlich funktioniert das für mich sehr gut. Ich hasse es, meine Projekte mit einer Menge aufgeblähter Unterklassen zu laden. Ich kann nicht sagen, ob dies die leistungsfähigste Lösung ist (ich habe immer gezögert, Code in scrollViewDidScroll einzufügen, da er ständig aufgerufen wird), aber der Code-Footprint ist der kleinste, den ich je gesehen habe Lösung für dieses Problem und es geht nicht darum, ein UITableView in einem UIScrollView zu verschachteln (Apple rät in der Dokumentation davon ab, und Touch-Events enden am UITableView etwas unkonventionell). Hoffe das hilft jemandem!

3
Brian

Ich habe versucht, GTScrollNavigationBar zu implementieren, aber für meine App musste ich die Einschränkungen für das automatische Layout ändern. Ich entschied mich, ein Beispiel für meine Implementierung auf GitHub zu veröffentlichen, falls dies bei Auto-Layout jemand anders tun soll. Das andere Problem, das ich bei den meisten anderen Implementierungen hatte, ist, dass Leute die Grenzen der Bildlaufansicht nicht festlegen, um den Parallax-Bildlaufeffekt zu vermeiden, den Sie beim Bildlauf erzeugen und gleichzeitig die Größe der Bildlaufansicht anpassen.

Check out JSCollapsingNavBarViewController wenn Sie dies mit automatischem Layout machen müssen. Ich habe zwei Versionen hinzugefügt, eine nur mit der Navigationsleiste und eine andere mit einer Hilfsleiste unterhalb der Navigationsleiste, die vor dem Zusammenbruch der Navigationsleiste zusammenbricht.

2
jwswart

ich habe es mit diesem Weg ausprobiert, ich hoffe, es hilft

-(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
user2968901

Eine Erweiterung der Antwort von @Iwburk ... Anstatt den Ursprung der Navigationsleiste zu ändern, musste ich die Navigationsleiste vergrößern/verkleinern.

- (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;
}

Es funktioniert noch nicht mit der stoppedScrolling-Methode, ich werde ein Update posten, wenn ich es habe

1
jsetting32

All diese Ansätze scheinen zu kompliziert zu sein ... Also habe ich natürlich meine eigenen aufgebaut:

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
    }

}
0
Oxcug

Ich habe alle Antworten in Objective-C gefunden. Dies ist meine Antwort in Swift 3. Dies ist ein sehr generischer Code und kann direkt verwendet werden. Es funktioniert sowohl mit UIScrollView als auch mit 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
    }
}

Die Logik, Alpha für Navigationselemente festzulegen, wird von @ WayneBurkett answer kopiert und in Swift 3 neu geschrieben.

0
Dev