Imita la barra di navigazione di espansione / contrazione nascondi / mostra di Facebook


128

Nella nuova app iOS7 di Facebook per iPhone, quando l'utente scorre verso l'alto navigationBarsi nasconde gradualmente fino a scomparire completamente. Quindi, quando l'utente scorre verso il basso, navigationBarsi mostra gradualmente.

Come implementeresti questo comportamento da solo? Sono a conoscenza della seguente soluzione, ma scompare immediatamente e non è affatto legata alla velocità del gesto di scorrimento dell'utente.

[navigationController setNavigationBarHidden: YES animated:YES];

Spero che questo non sia un duplicato in quanto non sono sicuro del modo migliore per descrivere il comportamento di "espansione / contrazione".


2
Stessi problemi: stackoverflow.com/questions/21929220/... notare che è incredibilmente difficile per assolutamente corrispondere al comportamento di Safari. Ci sono alcune regole molto, molto complicate!
Fattie,

1
Nel mio progetto ho usato questo progetto e ha funzionato bene. Dai un'occhiata alla sua documentazione.
Vinicio

github.com/bryankeller/BLKF FlexibleHeightBar ti consentirà di fare ciò che desideri e altro ancora. Ti consente di specificare esattamente come appare la barra in ogni fase della sua transizione da ingrandita a minimizzata. Ti consente anche di specificare i tuoi comportamenti, quindi può agire come Safari, Facebook o qualche altra app.
blkhp19,

Non ho usato una barra uinavigation ma ho invece aggiunto una vista uiview. La vista che replica la barra di navigazione si espande e si contrae in base allo scorrimento. Ho usato il metodo delegato scrollViewDidScroll per raggiungere il compito. Potresti voler controllare ed eseguire il codice sorgente di seguito .. dropbox.com/s/b2c0zw6yvchaia5/FailedBanks.zip?dl=0
Deepak Thakur

Risposte:


162

La soluzione fornita da @peerless è un ottimo inizio, ma dà il via a un'animazione ogni volta che inizia il trascinamento, senza considerare la velocità dello scorrimento. Ciò si traduce in un'esperienza più incisiva di quella che si ottiene nell'app Facebook. Per abbinare il comportamento di Facebook, dobbiamo:

  • nasconde / mostra la barra di navigazione a una velocità proporzionale alla velocità di trascinamento
  • dare il via a un'animazione per nascondere completamente la barra se lo scorrimento si interrompe quando la barra è parzialmente nascosta
  • sbiadiscono gli oggetti della barra di navigazione mentre la barra si restringe.

Innanzitutto, avrai bisogno della seguente proprietà:

@property (nonatomic) CGFloat previousScrollViewYOffset;

E qui ci sono i UIScrollViewDelegatemetodi:

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

Avrai anche bisogno di questi metodi di supporto:

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

Per un comportamento leggermente diverso, sostituire la linea che riposiziona la barra durante lo scorrimento (il elseblocco in scrollViewDidScroll) con questo:

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

Ciò posiziona la barra in base all'ultima percentuale di scorrimento, anziché a un valore assoluto, con una dissolvenza più lenta. Il comportamento originale è più simile a Facebook, ma mi piace anche questo.

Nota: questa soluzione è solo per iOS 7+. Assicurati di aggiungere i controlli necessari se stai supportando le versioni precedenti di iOS.


Questo funziona Ad eccezione del fatto che si presume che gli elementi del pulsante della barra abbiano viste personalizzate. Nel mio caso non ho una vista personalizzata. Quindi quanto sopra non nasconde i pulsanti della barra. Penso che la soluzione @peerless sia migliore per nascondere e mostrare gli elementi della barra di navigazione
Dhanush,

1
Hai ragione. Potrei cercare una soluzione più generale questo fine settimana. Non dovrebbe essere troppo difficile scegliere come target gli elementi predefiniti anziché customView.
Wayne,

Non ho affrontato il problema di @Dhanush ma ho un aggiornamento.
Wayne,

1
Ho risolto il problema con i pulsanti della barra stock, ma questo codice ha un altro problema. Se ScrollView's contentSizeè più piccolo di frame, l'animazione di scorrimento non funziona. Assicurati inoltre di reimpostare tutti gli alfa dell'elemento di navigazione su 1,0 pollici viewDidDisappear.
Legoless

1
Hai controllato questa soluzione sui controller che utilizzano AutoLayout? Nel mio caso tutto funziona bene senza AutoLayout, ma quando si accende, è ancora visibile una strana striscia bianca sotto di essa
Aliaksandr B.

52

EDIT: solo per iOS 8 e versioni successive.

Puoi provare ad usare

self.navigationController.hidesBarsOnSwipe = YES;

Per me va bene.

Se la tua codifica è rapida, devi utilizzare in questo modo (da https://stackoverflow.com/a/27662702/2283308 )

navigationController?.hidesBarsOnSwipe = true

questo non è disponibile in iOS <8.0
Petar

1
Come diceva pet60t0, e mi scuso, funziona solo per iOS 8 e versioni successive.
Pedro Romão,

4
Come lo riporti dopo?
C0D3,

il comportamento è un po 'strano. Non ho esplorato molto, ma se scorri più velocemente, lo mostra di nuovo.
Pedro Romão,

@ PedroRomão ottima risposta.
Gagan_iOS,

43

Ecco un'altra implementazione: rilasciato TLYShyNavBar v1.0.0!

Ho deciso di crearne uno mio dopo aver provato le soluzioni fornite e, per me, o stavano funzionando male, avevano un'alta barriera di ingresso e codice della piastra della caldaia, o mancava la vista dell'estensione sotto la barra di navigazione. Per utilizzare questo componente, tutto ciò che devi fare è:

self.shyNavBarManager.scrollView = self.scrollView;

Oh, ed è testato in battaglia nella nostra app.


@TimArnold Grazie per il tuo feedback! Ho risolto il problema, ma non ho ancora aggiornato il pod> _ <lo farà ora! .. Pod aggiornato!
Mazyod,

Ci proverò ancora! Grazie!
Tim Camber,

Apprezzo il vostro aiuto. Sembra che il tuo commit sia stato d'aiuto. Sto ancora riscontrando uno strano problema in cui il mio UICollectionView non viene ridimensionato correttamente come la barra di navigazione, e quindi le celle che salgono dove si trova la barra di navigazione USATA per essere tagliate, poiché sono al di fuori dei limiti della vista della raccolta. Sai perché questo potrebbe accadere?
Tim Camber,

4
Figure: ho trovato la mia soluzione pochi secondi dopo aver scritto questo commento. Ho dovuto assicurarmi che extendedLayoutIncludesOpaqueBarsfosse impostato YESsul mioUICollectionViewController
Tim Camber il

@TimArnold È fantastico! C'era un altro ragazzo con lo stesso problema , e spero che la tua soluzione lo aiuti.
Mazyod,

33

Puoi dare un'occhiata al mio GTScrollNavigationBar . Ho sottoclassato UINavigationBar per farlo scorrere in base allo scorrimento di un UIScrollView.

Nota: se si dispone di una barra di navigazione OPAQUE, la vista di scorrimento deve ESPANDERE man mano che la barra di navigazione viene NASCOSTA. Questo è esattamente ciò che fa GTScrollNavigationBar. (Proprio come ad esempio Safari su iOS.)


BTW per la lettura a nessuno, esattamente come chiamare initWithNavigationBarClass ... stackoverflow.com/questions/22286166
Fattie

@Thuy ottimo lavoro uomo! Quindi sto lavorando perfettamente su un controller di visualizzazione tabella tranne una cosa ... Ho tirato per aggiornare implementato nella parte superiore. Diventa strano quando si tenta di abbassare e aggiornare. Potrebbe esserci una soluzione per questo?
aherrick,

@Thuy anche ... diciamo che avevo un controller di visualizzazione in cui ho implementato una vista tabella in basso. Voglio collegarmi a quella vista tabella che funziona, tuttavia ho un'altra vista che è seduta sopra la vista tabella che voglio scomparire anch'essa. Come potrebbe funzionare?
aherrick,

25

iOS8 include proprietà per nascondere gratuitamente la barra di navigazione. C'è un video WWDC che lo dimostra, cerca "Visualizza i progressi del controller in iOS 8".

Esempio :

class QuotesTableViewController: UITableViewController {

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

    navigationController?.hidesBarsOnSwipe = true
}

}

Altre proprietà:

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

Trovato via http://natashatherobot.com/navigation-bar-interactions-ios8/


12

Ho una specie di soluzione rapida e sporca per quello. Non ho fatto alcun test approfondito ma ecco l'idea:

Quella proprietà manterrà tutti gli elementi nella barra di navigazione per la mia classe UITableViewController

@property (strong, nonatomic) NSArray *navBarItems;

Nella stessa classe UITableViewController ho:

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

Questo è solo per iOS> = 7, è brutto lo so, ma un modo rapido per raggiungere questo obiettivo. Eventuali commenti / suggerimenti sono benvenuti :)


12

Funziona con iOS 8 e versioni successive e garantisce che la barra di stato mantenga ancora lo sfondo

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

E se vuoi mostrare la barra di navigazione quando tocchi la barra di stato puoi farlo:

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

10

Ecco la mia implementazione: SherginScrollableNavigationBar .

Nel mio approccio sto usando KVOper osservare lo UIScrollViewstato, quindi non è necessario usare un delegato (e puoi usarlo per qualsiasi altra cosa tu abbia bisogno).


Cordiali saluti, questo non funziona sempre correttamente. Ho provato anche questo e funziona finché non si "rimbalza" sulla vista di scorrimento. Sembra che KVO non venga attivato quando si trova nella parte di rimbalzo. La chiamata delegata per contentOffset viene comunque attivata.
Joris Mans,

7

Per favore prova questa mia soluzione e fammi sapere perché non è buono come le risposte precedenti.

- (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
Ho fatto qualcosa di simile a questo, e questa è facilmente la soluzione migliore. Ho provato diversi hack e librerie, e questo è l'unico che funziona per iOS 9 con un tableView che non copre l'intero schermo. Complimenti!
skensell,

6

Un modo in cui l'ho realizzato è il seguente.

Registra il tuo controller di visualizzazione per essere il UIScrollViewDelegatetuo UITableViewper esempio.

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

Da de UIScrollViewDelegatemetodi è possibile ottenere il nuovo contentOffset e tradurlo di conseguenza UINavigationBarsu o giù.

L'impostazione dell'alfa delle visualizzazioni secondarie può anche essere effettuata in base ad alcuni valori di soglia e fattori che è possibile impostare e calcolare.

Spero che sia d'aiuto!


Abbiamo trovato post simili qui
Diana Sule,

Grazie Diana! Sospettavo che avrei dovuto implementare i metodi UIScrollViewDelegate ma sembrava che potesse essere un po 'eccessivo. Una volta che avrò capito questa cosa, la pubblicherò. Saluti!
El Mocoso,

4

Oltre alla risposta di Iwburk, ho aggiunto quanto segue per risolvere il problema alfa su barre di navigazione non personalizzate e ripristinare la barra di navigazione nel metodo 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];
}

Esiste un modo diverso dal passare in rassegna le sottoview?
thisiscrazy4,

Da quello che potrei dire su una barra di navigazione non personalizzata ci sono 4 visualizzazioni secondarie totali: _UINavigationBarBackground, UINavigationItemView, UINavigationItemButtonView e _UINavigationBarBackIndicatorView. Il ciclo è piuttosto rapido e non sembra influire sulle prestazioni della mia app.
blueice

Poiché _UINavigationBarBackground sembra essere sempre la prima sottoview, puoi semplicemente accedere direttamente al resto: ((UIView *) self.navigationController.navigationBar.subviews [1]). Alpha = alpha;
blueice

4

Stavo cercando una soluzione che consentisse qualsiasi stile e comportamento. Noterai che il comportamento di condensazione della barra è diverso in molte app diverse. E, naturalmente, l'aspetto della barra è totalmente diverso tra le app.

Ho creato una soluzione per questo problema con https://github.com/bryankeller/BLKF FlexibleHeightBar/

Puoi definire le tue regole di comportamento per controllare come e quando la barra si restringe e cresce, e puoi definire esattamente come vuoi che le visualizzazioni secondarie della barra reagiscano alla condensazione o alla crescita della barra.

Dai un'occhiata al mio progetto se vuoi molta flessibilità per creare qualsiasi tipo di barra di intestazione che puoi pensare.


Come posso aggiungere un pulsante a questo CustomHeaderView che si nasconderà quando scorro verso l'alto. Non ho bisogno di un pulsante statico. È possibile? Ho provato a creare un pulsante come sottoview. Ma non riceve alcun tocco.
abhimuralidharan,

3

Stavo cercando di emulare questo comportamento in una situazione in cui avevo bisogno di un'intestazione personalizzata che si trovasse su un UITableView. Ho aperto la mia barra di "navigazione" perché si trova sotto un mucchio di altre cose sulla pagina e volevo che le intestazioni di sezione seguissero il comportamento predefinito di "docking". Penso di aver trovato un modo abbastanza intelligente e succinto per regolare UITableView / UIScrollView insieme a un altro oggetto in uno stile simile a quello visto in Facebook / Instagram / Chrome / ecc. Apps.

Nel mio file .xib, ho i miei componenti caricati in una vista a mano libera: http://imgur.com/0z9yebJ (scusate, non ho il rappresentante per le immagini incorporate)

Si noti che, nella barra laterale di sinistra, la tabella è ordinata dietro la vista dell'intestazione principale. Non puoi dirlo dallo screenshot, ma ha anche la stessa posizione y della vista dell'intestazione principale. Poiché si estende fuori dalla vista, la proprietà contentInset su UITableView è impostata su 76 (l'altezza della vista dell'intestazione principale).

Per far scorrere la vista dell'intestazione principale all'unisono con UIScrollView, utilizzo i metodi scrollViewDidScroll di UIScrollViewDelegate per eseguire alcuni calcoli e modificare il contenuto di UIScrollViewInset e il frame della vista di intestazione principale.

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

La prima istruzione if svolge la maggior parte del lavoro pesante, ma ho dovuto includere le altre due per gestire le situazioni in cui l'utente sta trascinando forzatamente e i valori del contenuto inizialeOffset inviati a scrollViewDidScroll sono al di fuori dell'intervallo della prima istruzione if .

In definitiva, questo funziona davvero bene per me. Odio caricare i miei progetti con un mucchio di sottoclassi gonfie. Non posso dire se questa sia la migliore soluzione dal punto di vista delle prestazioni (sono sempre stato riluttante a inserire qualsiasi codice in scrollViewDidScroll poiché viene chiamato tutto il tempo), ma l'impronta del codice è la più piccola che abbia mai visto in soluzione per questo problema e non comporta l'annidamento di un UITableView in un UIScrollView (Apple sconsiglia questo nella documentazione e gli eventi di tocco finiscono un po 'funky su UITableView). Spero che questo aiuti qualcuno!



2

Ho provato a implementare GTScrollNavigationBar ma la mia app mi ha richiesto di modificare i vincoli di layout automatico. Ho deciso di mettere un esempio della mia implementazione su GitHub nel caso in cui qualcun altro debba farlo con il layout automatico. L'altro problema che ho avuto con la maggior parte delle altre implementazioni è che le persone non impostano i limiti della vista di scorrimento per evitare l'effetto di scorrimento della parallasse che si crea mentre si scorre e si regola contemporaneamente la dimensione della vista di scorrimento.

Dai un'occhiata a JSCollapsingNavBarViewController se devi farlo con il layout automatico. Ho incluso due versioni, una solo con la barra di navigazione e l'altra con una barra secondaria sotto la barra di navigazione che collassa prima di far collassare la barra di navigazione.


1

l'ho provato in questo modo, spero che possa aiutare. implementare semplicemente il codice con il metodo delegato e impostarlo sulla vista / sottoview desiderata

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

Un'estensione della risposta di @Iwburk ... Invece di cambiare l'origine della barra di navigazione, avevo bisogno di espandere / ridurre le dimensioni della barra di navigazione.

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

Non funziona ancora con il stoppedScrollingmetodo, non posso pubblicare un aggiornamento quando ce l'ho


0

Tutti questi approcci sembrano eccessivamente complicati ... Quindi, naturalmente, ho costruito il mio:

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? Usi un'estensione sulla frameproprietà?
Ely

0

Ho trovato tutte le risposte fornite in Objective-C. Questa è la mia risposta in Swift 3. Questo è un codice molto generico e può essere utilizzato direttamente. Funziona con UIScrollView e 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
    }
}

La logica di impostare l'alfa per gli elementi di navigazione viene copiata dalla risposta di @ WayneBurkett e riscritta in Swift 3.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.