[ios] Facebook 숨기기 / 표시 확장 / 계약 탐색 모음 모방

새로운 iOS7 Facebook iPhone 앱에서 사용자가 위로 스크롤하면 navigationBar점차 사라지는 지점 까지 점차적으로 숨겨집니다. 그런 다음 사용자가 아래로 스크롤하면 navigationBar점차적으로 표시됩니다.

이 행동을 어떻게 직접 구현 하시겠습니까? 다음 해결책을 알고 있지만 즉시 사라지고 사용자의 스크롤 제스처 속도와 관련이 없습니다.

[navigationController setNavigationBarHidden: YES animated:YES];

“확장 / 축소”동작을 가장 잘 설명하는 방법을 잘 모르기 때문에 이것이 중복되지 않기를 바랍니다.



답변

@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를 지원하는 경우 필요한 검사를 추가하십시오.


답변

편집 : iOS 8 이상에서만 가능합니다.

당신은 사용을 시도 할 수 있습니다

self.navigationController.hidesBarsOnSwipe = YES;

나를 위해 작동합니다.

신속하게 코딩하는 경우이 방법을 사용해야합니다 ( https://stackoverflow.com/a/27662702/2283308 )

navigationController?.hidesBarsOnSwipe = true


답변

여기에 또 하나의 구현은 다음과 같습니다 TLYShyNavBar의 v1.0.0 개발자가 출시!

나는 제공된 솔루션을 시도한 후에 나 자신을 만들기로 결정했고, 나에게는 성능이 좋지 않았거나 진입 및 보일러 판 코드의 장벽이 높았거나 탐색 표시 줄 아래의 확장보기가 부족했습니다. 이 구성 요소를 사용하려면 다음을 수행하십시오.

self.shyNavBarManager.scrollView = self.scrollView;

아, 그것은 우리 자신의 응용 프로그램에서 전투 테스트되었습니다.


답변

GTScrollNavigationBar를 볼 수 있습니다 . UIScrollView의 스크롤을 기반으로 스크롤하도록 UINavigationBar를 서브 클래스 화했습니다.

참고 : OPAQUE 탐색 막대가있는 경우 탐색 막대가 숨겨 질 때 스크롤보기가 확장되어야합니다. 이것이 바로 GTScrollNavigationBar의 기능입니다. (예를 들어 iOS의 Safari와 같습니다.)


답변

iOS8에는 탐색 모음을 무료로 숨기는 속성이 포함되어 있습니다. 이를 보여주는 WWDC 비디오가 있습니다. “iOS 8의 View Controller Advancements”를 검색하십시오.

:

class QuotesTableViewController: UITableViewController {

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

    navigationController?.hidesBarsOnSwipe = true
}

}

다른 속성들 :

class UINavigationController : UIViewController {

    //... truncated

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

http://natashatherobot.com/navigation-bar-interactions-ios8/을 통해 발견


답변

나는 그것에 대한 빠르고 더러운 해결책이 있습니다. 심층 테스트를하지 않았지만 여기 아이디어가 있습니다.

이 속성은 내 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에만 해당됩니다. 모든 의견 / 제안을 환영합니다 🙂


답변

이것은 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;
}