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


128

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

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

[navigationController setNavigationBarHidden: YES animated:YES];

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


2
같은 문제 : stackoverflow.com/questions/21929220/... 주는 것을 믿을 수 없을만큼 어려운 합니다 절대적으로 사파리 동작을 일치합니다. 거기에는 매우 복잡한 규칙이 있습니다!
Fattie

1
내 프로젝트 에서이 프로젝트를 사용 했으며 정상적으로 작동했습니다. 설명서를 살펴보십시오.
Vinicius

github.com/bryankeller/BLKFlexibleHeightBar 는 당신이 원하는 것을 더 할 수있게 해줍니다 . 막대가 최대에서 최소로 전환되는 각 단계에서 막대가 어떻게 보이는지 정확하게 지정할 수 있습니다. 또한 자신 만의 동작을 지정할 수 있으므로 Safari, Facebook 또는 다른 앱처럼 작동 할 수 있습니다.
blkhp19

uinavigationbar를 사용하지 않고 대신 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 솔루션은 탐색 모음 항목을 숨기고 표시하는 데 더 좋습니다
Dhanush

1
네 말이 맞아 이번 주말에 더 일반적인 해결책을 찾아 볼 수 있습니다. 대신 기본 항목을 타겟팅하기가 어렵지 않아야합니다 customView.
Wayne

@Dhanush의 문제를 해결하지 못했지만 업데이트가 있습니다.
Wayne

1
스톡 바 버튼으로 문제를 해결했지만이 코드에는 다른 문제가 있습니다. 경우 ScrollView의가 contentSize프레임보다 작은, 슬라이드의 애니메이션이 작동하지 않습니다. 또한 모든 탐색 항목의 알파를 다시 1.0 인치로 재설정해야합니다 viewDidDisappear.
Legoless

1
AutoLayout이 사용되는 컨트롤러에서이 솔루션을 확인 했습니까? 내 경우에는 AutoLayout없이 모든 것이 잘 작동하지만 켜지면 여전히 그 아래에 이상한 흰색 스트립이 보입니다
.

52

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

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

self.navigationController.hidesBarsOnSwipe = YES;

나를 위해 작동합니다.

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

navigationController?.hidesBarsOnSwipe = true

이것은 iOS <8.0
Petar

1
pet60t0이 말했듯이 사과드립니다 .iOS 8 이상에서만 작동합니다.
Pedro Romão

4
그 후 어떻게 가져 오나요?
C0D3

그것은 조금 이상합니다. 많이 탐색하지는 않았지만 더 빠르게 스크롤하면 다시 표시됩니다.
Pedro Romão

@ PedroRomão 좋은 답변입니다.
Gagan_iOS

43

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

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

self.shyNavBarManager.scrollView = self.scrollView;

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


@TimArnold 의견을 보내 주셔서 감사합니다! 이 문제를 해결했지만 아직 포드를 업데이트하지 않았습니다.> _ <지금 바로 할 것입니다! .. 포드가 업데이트되었습니다!
Mazyod

나는 또 다른 기회를 줄 것이다! 감사!
Tim Camber

도와 주셔서 감사합니다. 커밋이 도움이 된 것 같습니다. 내비게이션 바처럼 UICollectionView의 크기가 올바르게 조정되지 않는 이상한 문제가 계속 발생하므로 내비게이션 바가 USED가 될 곳까지 올라가는 셀은 컬렉션 뷰 범위를 벗어나므로 클리핑됩니다. 왜 이런 일이 일어날 지 아십니까?
Tim Camber

4
수치 :이 의견을 쓴 후 몇 초 만에 해결책을 찾았습니다. 나는 내 위에 extendedLayoutIncludesOpaqueBars설정되어 있는지 확인 YES했다UICollectionViewController
Tim Camber

@TimArnold 대단해! 같은 문제 가있는 다른 사람이 있었고 희망적으로 솔루션이 그를 도울 것입니다.
Mazyod

33

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

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


읽는 사람을위한 BTW, 정확하게 initWithNavigationBarClass를 호출하는 방법 ... stackoverflow.com/questions/22286166
Fattie

@Thuy 위대한 일꾼! 그래서 나는 한 가지를 제외하고 테이블 뷰 컨트롤러에서 완벽하게 작동하고 있습니다. 끌어 당기고 새로 고치려고 할 때 이상합니다. 이에 대한 해결 방법이 있습니까?
aherrick

@Thuy도 ... 하단에 테이블 뷰를 구현 한 뷰 컨트롤러가 있다고 가정 해 보겠습니다. 작동하는 테이블 뷰에 연결하고 싶지만 테이블 뷰 위에 앉아있는 다른 뷰도 있습니다. 어떻게 작동할까요?
aherrick

25

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

:

class QuotesTableViewController: UITableViewController {

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

    navigationController?.hidesBarsOnSwipe = true
}

}

다른 속성들 :

class UINavigationController : UIViewController {

    //... truncated

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

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


12

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

이 속성은 내 UITableViewController 클래스의 탐색 모음에 모든 항목을 유지합니다.

@property (strong, nonatomic) NSArray *navBarItems;

동일한 UITableViewController 클래스에 다음이 있습니다.

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

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

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

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

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

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

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

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

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

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

그것은 ios> = 7에만 해당됩니다. 모든 의견 / 제안을 환영합니다 :)


12

이것은 iOS 8 이상에서 작동하며 상태 표시 줄이 여전히 배경을 유지하도록합니다.

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

상태 표시 줄을 탭 할 때 탐색 표시 줄을 표시하려면 다음을 수행하십시오.

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

10

여기 내 구현이 있습니다 : SherginScrollableNavigationBar .

내 접근 방식에서는 의 상태 KVO를 관찰 UIScrollView하는 데 사용하므로 대리자를 사용할 필요가 없습니다 (필요한 다른 용도 로이 대리자를 사용할 수 있습니다).


참고로 항상 올바르게 작동하지는 않습니다. 나도 이것을 시도하고 스크롤보기를 "수신하지 않는 한"작동합니다. 바운스 부분에서는 KVO가 트리거되지 않는 것 같습니다. contentOffset에 대한 델리게이트 호출이 트리거됩니다.
Joris Mans

7

이 솔루션을 사용 해보고 왜 이것이 이전 답변만큼 좋지 않은지 알려주세요.

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

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

1
나는 이것과 비슷한 것을했고, 이것은 가장 좋은 해결책입니다. 몇 가지 해킹과 라이브러리를 시도했지만 이것이 전체 화면을 다루지 않는 tableView로 iOS 9에서 작동하는 유일한 방법입니다. 명성!
skensell

6

내가 이것을 달성 한 방법은 다음과 같습니다.

로보기 컨트롤러를 등록 UIScrollViewDelegate하여의를 UITableView예를 들면.

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

de UIScrollViewDelegate메소드 내 에서 새로운 contentOffset을 가져 UINavigationBar와서 위 또는 아래로 번역 할 수 있습니다 .

일부 임계 값과 설정 및 계산할 수있는 요소를 기반으로 하위보기의 알파를 설정할 수도 있습니다.

그것이 도움이되기를 바랍니다!


비슷한 게시물을 여기
Diana Sule

고마워 다이아나! 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

내가 아닌 사용자 정의 네비게이션 바에서 말할 수있는 것에서 _UINavigationBarBackground, UINavigationItemView, UINavigationItemButtonView 및 _UINavigationBarBackIndicatorView의 총 4 가지 하위 뷰가 있습니다. 루프는 매우 빠르며 내 앱의 성능에 영향을 미치지 않는 것 같습니다.
blueice

_UINavigationBarBackground는 항상 첫 번째 하위 뷰인 것처럼 보이므로 나머지에 직접 액세스 할 수 있습니다. ((UIView *) self.navigationController.navigationBar.subviews [1]). alpha = alpha;
blueice

4

나는 어떤 스타일과 행동을 허용하는 솔루션을 찾고있었습니다. 많은 응용 프로그램에서 막대 응축 동작이 다르다는 것을 알 수 있습니다. 물론 막대 모양은 앱마다 완전히 다릅니다.

https://github.com/bryankeller/BLKFlexibleHeightBar/ 를 사용 하여이 문제에 대한 솔루션을 만들었습니다.

막대가 줄어들고 커지는 방법과시기를 제어하기 위해 고유 한 동작 규칙을 정의 할 수 있으며 막대의 하위 뷰가 막대에 응결되거나 성장하는 방식을 정확하게 정의 할 수 있습니다.

생각할 수있는 모든 종류의 헤더 막대를 만들 수있는 많은 유연성을 원한다면 내 프로젝트를 살펴보십시오.


이 customHeaderView에 버튼을 추가하여 스크롤 할 때 숨길 수 있습니다. 정적 버튼이 필요하지 않습니다. 가능한가? 하위 뷰로 하나의 버튼을 만들려고했지만 터치가 수신되지 않습니다.
abhimuralidharan

3

UITableView에 대한 사용자 정의 헤더가 필요한 상황 에서이 동작을 에뮬레이션하려고했습니다. 페이지의 다른 여러 항목 아래에 있고 섹션 헤더가 기본 "도킹"동작을 따르기를 원했기 때문에 내 "탐색"막대를 굴 렸습니다. UITableView / UIScrollView를 Facebook / Instagram / Chrome / etc와 비슷한 스타일로 다른 객체와 함께 UITableView / UIScrollView를 조정하는 매우 영리하고 간결한 방법을 찾았습니다. 앱.

내 .xib 파일에서 자유 구성 요소 뷰에 내 구성 요소를로드했습니다. http://imgur.com/0z9yebJ (죄송합니다.

왼쪽 사이드 바에서 테이블은 기본 헤더보기 뒤에 정렬됩니다. 스크린 샷에서 알 수는 없지만 기본 헤더보기와 동일한 y 위치도 있습니다. UITableView의 contentInset 속성은 보이지 않게 확장되므로 76 (메인 헤더 뷰의 높이)으로 설정됩니다.

UIScrollView와 함께 메인 헤더 뷰를 슬라이드 업하기 위해 UIScrollViewDelegate의 scrollViewDidScroll 메소드를 사용하여 계산을 수행하고 UIScrollView의 contentInset과 메인 헤더 뷰의 프레임을 변경합니다.

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

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

첫 번째 if 문은 대부분의 무거운 작업을 수행하지만 사용자가 강제로 끌고 scrollViewDidScroll에 전송 된 초기 contentOffset 값이 첫 번째 if 문 범위를 벗어난 상황을 처리하기 위해 다른 두 개를 포함해야했습니다 .

궁극적으로 이것은 나를 위해 정말 잘 작동합니다. 부풀어 오른 하위 클래스로 프로젝트를로드하는 것을 싫어합니다. 이것이 성능면에서 최상의 솔루션인지 여부에 대해 말할 수는 없습니다 (항상 호출되기 때문에 scrollViewDidScroll에 코드를 넣는 것을 주저했습니다).하지만 코드 풋 프린트는 내가 본 것 중 가장 작습니다 이 문제에 대한 해결책이며 UIScrollView에 UITableView를 중첩시키지 않아도됩니다 (Apple은 문서 및 터치 이벤트에서 UITableView에서 약간 펑키하게 만듭니다). 이것이 누군가를 돕기를 바랍니다!



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
    }

}

navigationBar.height? scrollView.height? frame호텔 에서 연장을 사용하십니까 ?
Ely

0

Objective-C에 주어진 모든 답을 찾았습니다. 이것은 Swift 3의 답변입니다. 이것은 매우 일반적인 코드이며 직접 사용할 수 있습니다. UIScrollView 및 UITableView와 함께 작동합니다.

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

override func viewDidLoad() {
    super.viewDidLoad()

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

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

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

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

    navigationBarFrame.origin.y = initial

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

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

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

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

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

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

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

탐색 항목으로 알파를 설정하는 논리는 @ WayneBurkett 답변 에서 복사 되어 Swift 3에서 다시 작성되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.