Development Tip

사용자 지정 컨테이너보기 컨트롤러에 포함 된 콘텐츠는 탐색 모음 아래에 있습니다.

yourdevel 2021. 1. 8. 22:26
반응형

사용자 지정 컨테이너보기 컨트롤러에 포함 된 콘텐츠는 탐색 모음 아래에 있습니다.


최신 정보

Tim의 답변에 따라 사용자 지정 컨테이너의 일부인 scrollview (또는 하위 클래스)가있는 각 뷰 컨트롤러에서 다음을 구현했습니다.

- (void)didMoveToParentViewController:(UIViewController *)parent
{
    if (parent) {
        CGFloat top = parent.topLayoutGuide.length;
        CGFloat bottom = parent.bottomLayoutGuide.length;

        // this is the most important part here, because the first view controller added 
        // never had the layout issue, it was always the second. if we applied these
        // edge insets to the first view controller, then it would lay out incorrectly.
        // first detect if it's laid out correctly with the following condition, and if
        // not, manually make the adjustments since it seems like UIKit is failing to do so
        if (self.collectionView.contentInset.top != top) {
            UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
            self.collectionView.contentInset = newInsets;
            self.collectionView.scrollIndicatorInsets = newInsets;
        }
    }

    [super didMoveToParentViewController:parent];
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

라는 사용자 지정 컨테이너보기 컨트롤러가 SegmentedPageViewController있습니다. 나는 이것을 UINavigationController's rootViewController.

의 목적은 NavController의 titleView로 설정된를 SegmentedPageViewController허용하여 UISegmentedControl다른 자식 뷰 컨트롤러간에 전환 할 수 있도록하는 것입니다 .

여기에 이미지 설명 입력

이러한 자식 뷰 컨트롤러는 모두 스크롤 뷰, 테이블 뷰 또는 컬렉션 뷰를 포함합니다.

첫 번째 뷰 컨트롤러가 제대로로드되고 탐색 모음 아래에 올바르게 배치 된 것을 발견했습니다. 그러나 새 뷰 컨트롤러로 전환하면 navbar가 존중되지 않고 뷰가 nav bar 아래에 설정됩니다.

여기에 이미지 설명 입력

우리는 자동 레이아웃과 인터페이스 빌더를 사용하고 있습니다. 생각할 수있는 모든 것을 시도했지만 일관된 해결책을 찾을 수 없습니다.

다음은 사용자가 분할 된 컨트롤을 탭할 때 첫 번째 뷰 컨트롤러를 설정하고 다른 뷰 컨트롤러로 전환하는 주요 코드 블록입니다.

- (void)switchFromViewController:(UIViewController *)oldVC toViewController:(UIViewController *)newVC
{
    if (newVC == oldVC) return;

    // Check the newVC is non-nil otherwise expect a crash: NSInvalidArgumentException
    if (newVC) {

        // Set the new view controller frame (in this case to be the size of the available screen bounds)
        // Calulate any other frame animations here (e.g. for the oldVC)
        newVC.view.frame = self.view.bounds;

        // Check the oldVC is non-nil otherwise expect a crash: NSInvalidArgumentException
        if (oldVC) {
            // **** THIS RUNS WHEN A NEW VC IS SET ****
            // DIFFERENT FROM FIRST VC IN THAT WE TRANSITION INSTEAD OF JUST SETTING


            // Start both the view controller transitions
            [oldVC willMoveToParentViewController:nil];
            [self addChildViewController:newVC];

            // Swap the view controllers
            // No frame animations in this code but these would go in the animations block
            [self transitionFromViewController:oldVC
                              toViewController:newVC
                                      duration:0.25
                                       options:UIViewAnimationOptionLayoutSubviews
                                    animations:^{}
                                    completion:^(BOOL finished) {
                                        // Finish both the view controller transitions
                                        [oldVC removeFromParentViewController];
                                        [newVC didMoveToParentViewController:self];
                                        // Store a reference to the current controller
                                        self.currentViewController = newVC;
                                    }];
        } else {

            // **** THIS RUNS WHEN THE FIRST VC IS SET ****
            // JUST STANDARD VIEW CONTROLLER CONTAINMENT

            // Otherwise we are adding a view controller for the first time
            // Start the view controller transition
            [self addChildViewController:newVC];

            // Add the new view controller view to the view hierarchy
            [self.view addSubview:newVC.view];

            // End the view controller transition
            [newVC didMoveToParentViewController:self];

            // Store a reference to the current controller
            self.currentViewController = newVC;
        }
    }

}

Your custom container view controller will need to adjust the contentInset of the second view controller according to your known navigation bar height, respecting the automaticallyAdjustsScrollViewInsets property of the child view controller. (You may also be interested in the topLayoutGuide property of your container - make sure it returns the right value during and after the view switch.)

UIKit is remarkably inconsistent (and buggy) in how it applies this logic; sometimes you'll see it perform this adjustment automatically for you by reaching multiple view controllers down in the hierarchy, but often after a custom container switch you'll need to do the work yourself.


This seems to all be a lot simpler than what people make out.

UINavigationController will set scrollview insets only while laying out subviews. addChildViewController: does not cause a layout, however, so after calling it, you just need to call setNeedsLayout on your navigationController. Here's what I do while switching views in a custom tab-like view:

[self addChildViewController:newcontroller];
[self.view insertSubview:newview atIndex:0];
[self.navigationController.view setNeedsLayout];

The last line will cause scrollview insets to be re-calculated for the new view controller's contents.


FYI in case anyone is having a similar problem: this issue can occur even without embedded view controllers. It appears that automaticallyAdjustsScrollViewInsets is only applied if your scrollview (or tableview/collectionview/webview) is the first view in their view controller's hierarchy.

나는 종종 배경 이미지를 갖기 위해 내 계층 구조에서 UIImageView를 먼저 추가합니다. 이렇게하면 viewDidLayoutSubviews에서 scrollview의 가장자리 삽입을 수동으로 설정해야합니다.

- (void) viewDidLayoutSubviews {
    CGFloat top = self.topLayoutGuide.length;
    CGFloat bottom = self.bottomLayoutGuide.length;
    UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
    self.collectionView.contentInset = newInsets;

}

더 나은 해결책을 찾았고 문서화되지 않은 UINavigationController 메서드를 사용했습니다.

#import <UIKit/UIKit.h>

@interface UINavigationController (ContentInset)


- (void) computeAndApplyScrollContentInsetDeltaForViewController:(UIViewController*) controller;

@end

#import "UINavigationController+ContentInset.h"

@interface UINavigationController()


- (void)_computeAndApplyScrollContentInsetDeltaForViewController:(id)arg1; 

@end


@implementation UINavigationController (ContentInset)

- (void) computeAndApplyScrollContentInsetDeltaForViewController:(UIViewController*) controller
{
    if ([UINavigationController instancesRespondToSelector:@selector(_computeAndApplyScrollContentInsetDeltaForViewController:)])
        [self _computeAndApplyScrollContentInsetDeltaForViewController:controller];
}

@end

그럼 이렇게 해

- (void) cycleFromViewController: (UIViewController*) oldC
                toViewController: (UIViewController*) newC
{
    [oldC willMoveToParentViewController:nil];                        
    [self addChildViewController:newC];
  
    [self transitionFromViewController: oldC toViewController: newC   
                              duration: 0.25 options:0
                            animations:^{
                                newC.view.frame = oldC.view.frame;                                    
                                [self.navigationController computeAndApplyScrollContentInsetDeltaForViewController:newC];
                            }
                            completion:^(BOOL finished) {
                                [oldC removeFromParentViewController];                  
                                [newC didMoveToParentViewController:self];
                            }];
}


edgesForExtendedLayout = []내 자녀 컨트롤러에 대한 설정 이 나를 위해 일했습니다.

참조 URL : https://stackoverflow.com/questions/19038949/content-falls-beneath-navigation-bar-when-embedded-in-custom-container-view-cont

반응형