Імітуйте приховування / показ розширення / показу контракту на панелі навігації у Facebook


128

У новому додатку для iOS7 Facebook iPhone, коли користувач прокручується вгору, navigationBarпоступово ховається до точки, коли він повністю зникає. Потім, коли користувач прокручує вниз, navigationBarпоступово проявляється.

Як би ти реалізував цю поведінку сам? Мені відомо наступне рішення, але воно зникає одразу і зовсім не пов'язане зі швидкістю жесту прокрутки користувача.

[navigationController setNavigationBarHidden: YES animated:YES];

Я сподіваюся, що це не дублікат, тому що я не впевнений, як найкраще описати поведінку "розширення / контрактування".


2
Ті ж питання: stackoverflow.com/questions/21929220 / ... Зверніть увагу , що неймовірно важко , щоб абсолютно відповідати поведінки Safari. Тут є дуже дуже складні правила!
Fattie

1
У своєму проекті я використав цей проект, і він спрацював чудово. Погляньте на його документацію.
Вініцій

github.com/bryankeller/BLKF FlexibleHeightBar дозволить вам робити те, що ви хочете, і багато іншого. Він дозволяє точно вказати, як виглядає панель на кожному етапі свого переходу від максимального до мінімізованого. Це навіть дозволяє вам вказати власну поведінку, тому вона може діяти як Safari, Facebook чи інша програма.
blkhp19

Я не використовував панель uinavigation, але натомість додав uiview. Вид, що повторює панель навігації, розшириться і скоротиться на основі прокрутки. Я використовував метод делегування scrollViewDidScroll для досягнення поставленого завдання. Ви можете перевірити та виконати вихідний код нижче .. dropbox.com/s/b2c0zw6yvchaia5/FailedBanks.zip?dl=0
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 рішення краще для приховування та відображення NavBar елементів
Дануш

1
Ти правий. Я можу розглянути більш загальне рішення у ці вихідні. Націлити на елементи за замовчуванням замість них не повинно бути надто складно customView.
Уейн

Я не звертався до проблеми @ Dhanush, але в мене є оновлення.
Уейн

1
Я виправив проблему за допомогою кнопок панелі запасів, але цей код має ще одну проблему. Якщо ScrollViews contentSizeменший за кадр, анімація ковзання не працює. Також переконайтеся, що ви скинули альфа всіх елементів навігації до 1,0 дюйма viewDidDisappear.
Безголосий

1
Ви перевірили це рішення на контролерах, які використовують AutoLayout? У моєму випадку все працює нормально без AutoLayout, але коли він увімкнеться, під ним все одно видно якась дивна біла смуга
Олександр Б.

52

EDIT: Тільки для iOS 8 і вище.

Можна спробувати використовувати

self.navigationController.hidesBarsOnSwipe = YES;

Працює для мене.

Якщо ваше кодування швидко, вам потрібно скористатися цим способом (з https://stackoverflow.com/a/27662702/2283308 )

navigationController?.hidesBarsOnSwipe = true

ця функція недоступна в iOS <8.0
Петра,

1
Як сказав pet60t0, і я вибачаюся, працює лише для iOS 8 і вище.
Педро Ромао

4
Як ви повернете це після цього?
C0D3

поведінка це трохи дивно. Я мало досліджував, але якщо прокрутити швидше, це знову з’явиться.
Педро Ромао

@ PedroRomão чудова відповідь.
Gagan_iOS

43

Ось ще одна реалізація: TLYShyNavBar v1.0.0 випущений!

Я вирішив зробити власне, спробувавши запропоновані рішення, і для мене вони або погано працювали, мали високий бар'єр для входу та код пластини котла, або не вистачало виду розширення під навивором. Щоб використовувати цей компонент, все, що вам потрібно зробити, це:

self.shyNavBarManager.scrollView = self.scrollView;

О, і це битви перевірені в нашому додатку.


@TimArnold Дякуємо за Ваш відгук! Я вирішив цю проблему, просто ще не оновлював стручок> _ <зробимо це прямо зараз! .. Pod оновлено!
Mazyod

Я ще пострілю! Дякую!
Тім Камбер

Я вдячний за твою допомогу. Схоже, ваша допомога допомогла. У мене все ще виникає дивна проблема, коли мій UICollectionView не змінено належним чином, як панель навігації, і тому клітини, що піднімаються там, де користується НАВИЧЕНИМ бар, будуть вибиті, оскільки вони знаходяться поза межами перегляду колекції. Чи знаєте ви, чому це може статися?
Тім Камбер

4
Цифри: знайшов своє рішення через секунди після написання цього коментаря. Я повинен був переконатися, що це extendedLayoutIncludesOpaqueBarsбуло встановлено YESна моємуUICollectionViewController
Тім Камбер

@TimArnold Це приголомшливо! З тією ж проблемою був ще один хлопець , і, сподіваємось, ваше рішення допоможе йому.
Мазюд

33

Ви можете подивитися на мій GTScrollNavigationBar . Я підкласирував UINavigationBar, щоб зробити його прокруткою на основі прокрутки UIScrollView.

Примітка. Якщо у вас є панель навігації OPAQUE, огляд прокрутки повинен РОЗШИРИТИ, оскільки панель навігації буде прихована. Саме цим займається GTScrollNavigationBar. (Так само, як, наприклад, Safari на iOS.)


До речі для будь-якого читає, як точно назвати initWithNavigationBarClass ... stackoverflow.com/questions/22286166
Fattie

@Такий чудовий чоловік! Тож у мене це ідеально працює на контролері подання таблиці, за винятком однієї речі ... Я маю тягнути для оновлення, реалізованого вгорі. Це стає дивно при спробі зняти і оновити. Чи може бути вирішення цього питання?
aherrick

@Так також ... скажемо, у мене був контролер перегляду, де я реалізував подання таблиці внизу. Я хочу підключитися до того виду таблиці, який працює, однак у мене є інший погляд, який сидить над поданням таблиці, який я також хочу зникнути. Як це може працювати?
aherrick

25

iOS8 включає властивості, щоб безкоштовно переховувати панель навігації. Є відео WWDC, яке демонструє це, шукайте "Переглянути вдосконалення контролера в iOS 8".

Приклад :

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за станом, тому немає необхідності використовувати делегата (і ви можете використовувати цього делегата для всього іншого, що вам потрібно).


FYI, це не завжди працює правильно. Я також спробував це, і це працює до тих пір, поки ви не "підстрибуєте" прокрутку. Здається, 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

6

Один із способів, що я це досяг, - це наступний.

Зареєструйте, наприклад, контролер перегляду, щоб він був UIScrollViewDelegateвашим UITableView.

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

Зсередини UIScrollViewDelegateметодів ви можете отримати новий contentOffset і перекласти свійUINavigationBar вгору або вниз.

Встановлення альфа субперегляду також може здійснюватися на основі деяких порогових значень та факторів, які можна встановити та обчислити.

Сподіваюся, це допомагає!


Знайшов подібний пост тут
Діана Суле

Дякую Діані! Я підозрював, що мені доведеться реалізувати методи UIScrollViewDelegate, але, здавалося, це може бути трохи зайвим. Як тільки я зрозумію цю річ, я викладу її. Ура!
El Mocoso

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

З того, що я міг би сказати на непристосованій панелі навігації, є 4 загальних підгляди: _UINavigationBarBackground, UINavigationItemView, UINavigationItemButtonView та _UINavigationBarBackIndicatorView. Цикл досить швидкий і, схоже, не впливає на ефективність мого додатка.
blueice

Оскільки _UINavigationBarBackground, як видається, завжди є першим підвідбором, ви можете просто отримати доступ до решти безпосередньо: ((UIView *) self.navigationController.navigationBar.subviews [1]). Alpha = alpha;
blueice

4

Я шукав рішення, яке дозволило б будь-який стиль та будь-яку поведінку. Ви помітите, що поведінка конденсації смуги різна в багатьох різних програмах. І звичайно, те, як виглядає смужка, абсолютно відрізняється між додатками.

Я створив рішення цієї проблеми за допомогою https://github.com/bryankeller/BLKFfleHeightBar/

Ви можете визначити свої власні правила поведінки, щоб контролювати, як і коли планка скорочується і росте, і ви можете точно визначити, як ви хочете, щоб підгляди бару реагували на конденсацію або зростання бар.

Погляньте на мій проект, якщо ви хочете багато гнучкості, щоб зробити будь-який вид заголовка, який ви можете придумати.


Як я можу додати кнопку до цього customHeaderView, який буде приховано, коли я прокручую вгору. Мені не потрібна статична кнопка. Чи можливо це? Я спробував створити одну кнопку як підзагляд. Але вона не отримує ніяких дотиків.
абхімуралідхаран

3

Я намагався наслідувати цю поведінку в ситуації, коли мені потрібен індивідуальний заголовок, що сидить біля UITableView. Я прокрутив власну панель "навігації", тому що вона розташована нижче ряду інших матеріалів на сторінці, і я хотів, щоб заголовки розділів дотримувались стандартної поведінки "стикування". Я думаю, що я знайшов досить розумний та лаконічний спосіб налаштувати UITableView / UIScrollView разом з іншим об’єктом у стилі, подібному до того, що спостерігається у Facebook / Instagram / Chrome / тощо. додатки.

У моєму .xib файлі мої компоненти завантажуються у вільну форму перегляду: http://imgur.com/0z9yebJ (вибачте, у мене немає реплікації для вбудованих зображень)

Зауважте, що на лівій бічній панелі таблиця впорядкована за основним поданням заголовка. З екрана екрана ви не можете розпізнати, але він також має таке ж положення y, як і головний вигляд заголовка. Оскільки воно поширюється з поля зору, властивість contentInset у UITableView встановлено на 76 (висота подання головного заголовка).

Для того, щоб перегляд головного заголовка просувався в унісон з UIScrollView, я використовую методи scrollViewDidScroll UIScrollViewDelegate для виконання деяких обчислень та зміни змісту Inset UIScrollView, а також кадру головного заголовка.

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

Перший, якщо заява робить більшу частину важкого підйому, але мені довелося включити два інших, щоб обробити ситуації, коли користувач насильно перетягується, а початкові значення contentOffset, що надсилаються на scrollViewDidScroll, виходять за межі діапазону першого, якщо оператора .

Зрештою, це працює дуже добре для мене. Я ненавиджу завантажувати свої проекти з купою роздутих підкласів. Я не можу говорити, чи це найкраще рішення щодо ефективності рішення (я завжди вагався вводити будь-який код у scrollViewDidScroll, оскільки він постійно називається), але слід коду є найменшим, що я бачив у будь-якому рішення цієї проблеми, і це не передбачає вкладання UITableView в UIScrollView (Apple радить цього не робити в документації, а події дотику в кінцевому підсумку виявляються трохи привабливими для UITableView). Сподіваюся, це допоможе комусь!


3

HidingNavigationBar - чудовий проект, який приховує панель навігації та панель вкладок, якщо ви хочете.

HidingNavigationBar підтримує приховування / показ таких елементів перегляду:

UINavigationBar

UINavigationBar та розширення UIView

UINavigationBar та панель UITool

UINavigationBar і UITabBar

https://github.com/tristanhimmelman/HidingNavigationBar


2

Я спробував реалізувати GTScrollNavigationBar, але мій додаток вимагав від мене змінити обмеження щодо автоматичного макета. Я вирішив прикласти мою реалізацію на GitHub у випадку, якщо хтось інший повинен це зробити з автоматичним компонуванням. Інша проблема, з якою у мене виникли більшість інших реалізацій, полягає в тому, що люди не встановлюють межі подання прокрутки, щоб уникнути ефекту прокрутки паралакса, який ви створюєте під час прокрутки та регулювання розміру прокрутки одночасно.

Ознайомтеся з JSCollapsingNavBarViewController, якщо вам потрібно зробити це з автоматичним компонуванням. Я включив дві версії: одну лише з панелью навігації, а іншу з підпунктом нижче панелі навігації, який згортається перед тим, як згортати панель навігації.


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
    }

}

навігаціяBar.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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.