IT박스

iOS 11 iPhone X 시뮬레이터 UITabBar 아이콘과 제목이 서로를 덮고 위에 렌더링됩니다.

itboxs 2020. 7. 5. 08:16
반응형

iOS 11 iPhone X 시뮬레이터 UITabBar 아이콘과 제목이 서로를 덮고 위에 렌더링됩니다.


UITabBar 구성 요소와 관련하여 iPhone X 시뮬레이터에 문제가 있습니까?

내 아이콘과 제목을 서로 렌더링하는 것처럼 보입니다. 내가 빠진 것이 확실하지 않은 경우 iPhone 8 시뮬레이터에서 실행 한 것과 실제 장치가 그림과 같이 잘 보입니다. 스토리 보드.

아이폰 X :

iPhone X UITabBar 버그

아이폰 8

아이폰 8 UITabBar 작동


viewDidLayoutSubviews의 UITabBar에서 invalidateIntrinsicContentSize를 호출하여 문제를 해결할 수있었습니다.

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self.tabBar invalidateIntrinsicContentSize];
}

참고 : 탭 막대의 아래쪽은 안전 영역이 아니라 기본보기의 아래쪽에 포함되어야하며 탭 막대에는 높이 제한이 없어야합니다.


VoidLess가 제공 한 답변은 TabBar 문제를 부분적으로 만 해결합니다. 탭 막대 내에서 레이아웃 문제를 해결하지만 탭 막대를 숨기는 뷰 컨트롤러를 사용하는 경우 애니메이션 중에 탭 막대가 잘못 렌더링됩니다 (재생하는 것이 가장 좋습니다. 제자리에서 렌더링되는 탭바 참조). 다음 코드는 두 가지 문제를 모두 해결합니다. 잘 했어.

class SafeAreaFixTabBar: UITabBar {

var oldSafeAreaInsets = UIEdgeInsets.zero

@available(iOS 11.0, *)
override func safeAreaInsetsDidChange() {
    super.safeAreaInsetsDidChange()

    if oldSafeAreaInsets != safeAreaInsets {
        oldSafeAreaInsets = safeAreaInsets

        invalidateIntrinsicContentSize()
        superview?.setNeedsLayout()
        superview?.layoutSubviews()
    }
}

override func sizeThatFits(_ size: CGSize) -> CGSize {
    var size = super.sizeThatFits(size)
    if #available(iOS 11.0, *) {
        let bottomInset = safeAreaInsets.bottom
        if bottomInset > 0 && size.height < 50 && (size.height + bottomInset < 90) {
            size.height += bottomInset
        }
    }
    return size
}

override var frame: CGRect {
    get {
        return super.frame
    }
    set {
        var tmp = newValue
        if let superview = superview, tmp.maxY != 
        superview.frame.height {
            tmp.origin.y = superview.frame.height - tmp.height
        }

        super.frame = tmp
        }
    }
}

오브젝티브 -C 코드 :

@implementation VSTabBarFix {
    UIEdgeInsets oldSafeAreaInsets;
}


- (void)awakeFromNib {
    [super awakeFromNib];

    oldSafeAreaInsets = UIEdgeInsetsZero;
}


- (void)safeAreaInsetsDidChange {
    [super safeAreaInsetsDidChange];

    if (!UIEdgeInsetsEqualToEdgeInsets(oldSafeAreaInsets, self.safeAreaInsets)) {
        [self invalidateIntrinsicContentSize];

        if (self.superview) {
            [self.superview setNeedsLayout];
            [self.superview layoutSubviews];
        }
    }
}

- (CGSize)sizeThatFits:(CGSize)size {
    size = [super sizeThatFits:size];

    if (@available(iOS 11.0, *)) {
        float bottomInset = self.safeAreaInsets.bottom;
        if (bottomInset > 0 && size.height < 50 && (size.height + bottomInset < 90)) {
            size.height += bottomInset;
        }
    }

    return size;
}


- (void)setFrame:(CGRect)frame {
    if (self.superview) {
        if (frame.origin.y + frame.size.height != self.superview.frame.size.height) {
            frame.origin.y = self.superview.frame.size.height - frame.size.height;
        }
    }
    [super setFrame:frame];
}


@end

문제를 해결할 수있는 방법이 있습니다.

UITabBar를 UIView 안에 넣으십시오.

이것은 실제로 나를 위해 일하고 있습니다.

또는 자세한 내용 은이 링크 를 참조하십시오.


우선 UITabBar sizeThatFits(_)safeArea에 대한

extension UITabBar {
    static let height: CGFloat = 49.0

    override open func sizeThatFits(_ size: CGSize) -> CGSize {
        guard let window = UIApplication.shared.keyWindow else {
            return super.sizeThatFits(size)
        }
        var sizeThatFits = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            sizeThatFits.height = UITabBar.height + window.safeAreaInsets.bottom
        } else {
            sizeThatFits.height = UITabBar.height
        }
        return sizeThatFits
    }
}

제공된 답변 중 어느 것도 나를 위해 일하지 않았기 때문에 이것을 viewWillAppear내 custom에 추가 UITabBarController했습니다.

tabBar.invalidateIntrinsicContentSize()
tabBar.superview?.setNeedsLayout()
tabBar.superview?.layoutSubviews()

탭 막대를 아래쪽에서 1 포인트 이동하면 나에게 도움이되었습니다.

물론 어떤 식 으로든 채워야하지만 텍스트 / 아이콘이 올바르게 배치되어 간격이 생깁니다.


나는 같은 문제가 있었다.

여기에 이미지 설명을 입력하십시오

UITabBar의 하단 제약 조건에서 0이 아닌 상수를 안전 영역으로 설정하면 :

여기에 이미지 설명을 입력하십시오

예상대로 작동하기 시작합니다 ...

여기에 이미지 설명을 입력하십시오

그것이 내가 한 유일한 변화이며 그것이 왜 효과가 있는지 전혀 알지 못하지만 누군가가 알고 싶다면 알고 싶습니다.


safeAreaInsets를 적용하기 위해 서브 클래 싱 된 UITabBar를 사용하여 수정되었습니다.

class SafeAreaFixTabBar: UITabBar {

    var oldSafeAreaInsets = UIEdgeInsets.zero

    @available(iOS 11.0, *)
    override func safeAreaInsetsDidChange() {
        super.safeAreaInsetsDidChange()

        if oldSafeAreaInsets != safeAreaInsets {
            oldSafeAreaInsets = safeAreaInsets

            invalidateIntrinsicContentSize()
            superview?.setNeedsLayout()
            superview?.layoutSubviews()
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var size = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            let bottomInset = safeAreaInsets.bottom
            if bottomInset > 0 && size.height < 50 {
                size.height += bottomInset
            }
        }
        return size
    }
}

아하! 실제로 마술이다!

나는 마침내 애플을 저주 한 몇 시간 후에 이것을 알아 냈다.

UIKit은 실제로 이것을 처리하며 변경된 탭 막대 항목은 잘못된 설정 (및 실제 UIKit 버그)으로 인한 것으로 보입니다. 서브 클래 싱 또는 백그라운드 뷰가 필요하지 않습니다.

UITabBar가 맨 아래 안전 영역 이 아니라 슈퍼 뷰의 맨 아래로 제한되면 "작동"합니다 .

심지어 인터페이스 빌더에서도 작동합니다.

올바른 설정

IB에서 일하기

  1. 인터페이스 빌더에서 iPhone X로 볼 때 UITabBar를 아래쪽 안전 영역 삽입 위치에 스냅되는 위치로 드래그하십시오. 떨어 뜨릴 때 올바르게 보입니다 (하단 가장자리까지 공간을 채 웁니다).
  2. 그런 다음 "누락 된 구속 조건 추가"를 수행하면 IB가 올바른 구속 조건을 추가하고 탭 막대가 모든 iPhone에서 마술처럼 작동합니다! (하단 제약 조건은 iPhone X 안전하지 않은 영역의 높이와 동일한 상수 값을 갖지만 상수는 실제로 0입니다.)

때로는 여전히 작동하지 않습니다

IB에서 고장

정말 멍청한 것은 IB가 위의 단계에서 추가하는 정확한 제약 조건을 추가하더라도 IB의 버그를 실제로 볼 수 있다는 것입니다!

  1. UITabBar를 드래그하여 하단 안전 영역에 스냅하지 마십시오.
  2. 선행, 후행 및 하단 제약 조건을 모두 슈퍼 뷰 (안전 영역이 아님)에 추가하는 것이 이상하게, 하단 제약 조건에 대해 제약 조건 관리자에서 "첫 번째 및 두 번째 항목 반전"을 수행하면 자동으로 수정됩니다. ¯_ (ツ) _ / ¯

[tabController.view setNeedsLayout];완료 블록에서 모달을 해제 한 후 전화하여 나를 해결했습니다 .

[vc dismissViewControllerAnimated:YES completion:^(){ 
     UITabBarController* tabController = [UIApplication sharedApplication].delegate.window.rootViewController;
     [tabController.view setNeedsLayout];
}];

UITabBar의 높이가 홈 버튼 / 라인 위로 올라가고 있지만 하위 뷰를 원래 위치에 그리고 하위 뷰 위에 UITabBarItem을 오버레이합니다.

이 문제를 해결하려면 iPhone X를 감지 한 다음보기의 높이를 32 픽셀로 축소하여 홈 표시 줄의 안전 영역에 탭 막대가 표시되도록하십시오.

예를 들어 프로그래밍 방식으로 TabBar를 만드는 경우

self.tabBarController = [[UITabBarController alloc] init];
self.window.rootViewController = self.tabBarController;

이것으로 :

#define IS_IPHONEX (([[UIScreen mainScreen] bounds].size.height-812)?NO:YES)
self.tabBarController = [[UITabBarController alloc] init];    
self.window.rootViewController = [[UIViewController alloc] init] ;
if(IS_IPHONEX)
    self.window.rootViewController.view.frame = CGRectMake(self.window.rootViewController.view.frame.origin.x, self.window.rootViewController.view.frame.origin.y, self.window.rootViewController.view.frame.size.width, self.window.rootViewController.view.frame.size.height + 32) ;
[self.window.rootViewController.view addSubview:self.tabBarController.view];
self.tabBarController.tabBar.barTintColor = [UIColor colorWithWhite:0.98 alpha:1.0] ;
self.window.rootViewController.view.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1.0] ;

참고 :보기 크기와 탭 막대 레이아웃이 OS에 의해 설정되므로 버그 일 수 있습니다. iPhone X 휴먼 인터페이스 가이드 라인 ( https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/) 에서 Apple의 스크린 샷에 따라 표시되어야합니다.


내 경우는 UITabBarController에서 사용자 정의 UITabBar 높이를 다음과 같이 설정했다는 것입니다.

  override func viewWillLayoutSubviews() {            
        var tabFrame = tabBar.frame
        tabFrame.size.height = 60
        tabFrame.origin.y = self.view.frame.size.height - 60
        tabBar.frame = tabFrame
    }

이 코드를 제거하면 iPhone X에서 TabBar가 올바르게 표시됩니다.


사용자 정의 TabBarController에서 UITabBar의 프레임을 설정하려고 할 때도 같은 문제가 발생했습니다.

self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kTabBarHeight, self.view.frame.size.width, kTabBarHeight);

방금 새로운 크기로 조정하면 문제가 사라졌습니다.

if(IS_IPHONE_X){
    self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kPhoneXTabBarHeight, self.view.frame.size.width, kPhoneXTabBarHeight);
}
else{
    self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kTabBarHeight, self.view.frame.size.width, kTabBarHeight);
}

오늘은 스토리 보드의 뷰 컨트롤러에 UITabBar를 수동으로 추가 하여이 문제가 발생했습니다. 안전 영역의 바닥에 상수 0을 맞추면 문제가 발생하지만 1로 변경하면 문제가 해결됩니다. UITabBar를 평소보다 1 픽셀 높이면 응용 프로그램에서 사용할 수있었습니다.


나는이 문제에 대해 머리를 긁었다. tabBar가 초기화되고 계층 구조를보기 위해 추가되는 방법과 관련이있는 것 같습니다. 또한 호출 invalidateIntrinsicContentSize, 프레임 설정 및 bottomInsetsUITabBar 하위 클래스 내부 같은 위의 솔루션을 시도했습니다 . 그러나 일시적으로 작동하는 것처럼 보이며 다른 시나리오를 위반하거나 모호한 레이아웃 문제를 일으켜 탭 표시 줄을 되돌립니다. 문제를 디버깅 할 때 UITabBar 및 centerYAnchor에 높이 제약 조건을 할당하려고 시도했지만 문제가 해결되지 않았습니다. 뷰 디버거에서 문제가 재현되기 전후에 tabBar 높이가 정확하다는 것을 깨달았으므로 문제가 하위보기에 있다고 생각하게되었습니다. 아래 코드를 사용하여 다른 시나리오를 회귀하지 않고이 문제를 성공적으로 해결했습니다.

- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    if (DEVICE_IS_IPHONEX())
    {
        [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            for (UIView *view in self.tabBar.subviews)
            {
                if ([NSStringFromClass(view.class) containsString:@"UITabBarButton"])
                {
                    if (@available (iOS 11, *))
                    {
                        [view.bottomAnchor constraintEqualToAnchor:view.superview.safeAreaLayoutGuide.bottomAnchor].active = YES;
                    }
                }
            }
        } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            [self.tabBar layoutSubviews];
        }];
    }
}

Assumptions: I am doing this only for iPhone X, since it doesn't seem to reproduce on any other device at the moment. Is based on the assumption that Apple doesn't change the name of the UITabBarButton class in future iOS releases. We're doing this on UITabBarButton only when means if apple adds more internal subviews in to UITabBar we might need to modify the code to adjust for that.

Please lemme know if this works, will be open to suggestions and improvements!

It should be simple to create a swift equivalent for this.


From this tutorial:

https://github.com/eggswift/ESTabBarController

and after initialization of tab bar writing this line in appdelegate class

(self.tabBarController.tabBar as? ESTabBar)?.itemCustomPositioning = .fillIncludeSeparator

Solves my problem of tab bar.

Hope its solves your problem

Thanks


Select tabbar and set "Save Area Relative Margins" checkbox in Inspector Editor like this:

여기에 이미지 설명을 입력하십시오


If you have any height constraint for the Tab Bar try removing it .

Faced the same problem and removing this solved the issue.


I created new UITabBarController in my storyboard and pushed all view controllers to this new UITabBarConttoller. So, all work well in iPhone X simulator.


For iPhone you can do this, Subclass UITabBarController.

class MyTabBarController: UITabBarController {

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if #available(iOS 11, *) {
        self.tabBar.heightAnchor.constraint(equalToConstant: 40).isActive = true
        self.tabBar.invalidateIntrinsicContentSize()
    }
  }
}

Goto Storyboard and allow Use Safe Area Layout Guide and change class of UITabbarController to MyTabBarController

P.S This solution is not tested in case of universal application and iPad.


try to change splash screen with @3x size is (3726 × 6624)


For me, remove [self.tabBar setBackgroundImage:] work, maybe it's UIKit bug


For me this fixed all the issues:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let currentHeight = tabBar.frame.height
        tabBar.frame = CGRect(x: 0, y: view.frame.size.height - currentHeight, width: view.frame.size.width, height: currentHeight)
    }

I had the similar problem, at first it was rendered correctly but after setting up badgeValue on one of the tabBarItem it broke the layout. What it worked for me without subclassing UITabBar was this, on my already created UITabBarController subclass.

-(void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    NSLayoutYAxisAnchor *tabBarBottomAnchor = self.tabBar.bottomAnchor;
    NSLayoutYAxisAnchor *tabBarSuperviewBottomAnchor = self.tabBar.superview.bottomAnchor;
    [tabBarBottomAnchor constraintEqualToAnchor:tabBarSuperviewBottomAnchor].active = YES;
    [self.view layoutIfNeeded];
}

I used tabBar superview to make sure that the constraints/anchors are on the same view hierarchy and avoid crashes.

Based on my understanding, since this seems to be a UIKit bug, we just need to rewrite/re-set the tab bar constraints so the auto layout engine can layout the tab bar again correctly.


The simplest solution I found was to simply add a 0.2 pt space between the bottom of the tab bar and the bottom of the safeAreaLayoutGuide.bottomAnchor like so.

tabBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -0.2)

I was using a UITabBarController in the storyboard and at first it was working alright for me, but after upgrading to newer Xcode version it started giving me issues related to the height of the tabBar.

For me, the fix was to delete the existing UITabBarController from storyboard and re-create by dragging it from the interface builder objects library.


I was having the same issue which was solved by setting the items of the tabBar after the tab bar was laid out.

In my case the issue happened when:

  1. There is a custom view controller
  2. A UITabBar is created in the initializer of the view controller
  3. The tab bar items are set before view did load
  4. In view did load the tab bar is added to the main view of the view controller
  5. Then, the items are rendered as you mention.

I think this is a bug UIKit from iPhoneX. because it works:

if (@available(iOS 11.0, *)) {
    if ([UIApplication sharedApplication].keyWindow.safeAreaInsets.top > 0.0) {
       self.tabBarBottomLayoutConstraint.constant = 1.0;
    }
} 

I believe you might be laying out the tab bar against the bottom safe layout guide. This is probably not what you want since the tab bar does seems to do its own calculations to position the tab bar items safely on top of the home line in the iPhone X. Setup your bottom constraint against the superview bottom. You should see that it lays out correctly on iPhone X as well as other iPhones.


I ran into this bug on my launch screen storyboard, which can't be customised via subclassing. After some analysis I managed to figure out the cause - I was using a UITabBar directly. Switching to a UITabBarController, which encapsulates a UITabBar, solved the issue.

참고-이것은 iOS 11.1에서 수정 될 수 있으므로 실제 iPhone X 앱에는 영향을 미치지 않을 수 있습니다 (iPhone X가 iOS 11.1을 실행하기 때문에 출시 될 가능성이 있기 때문에).

참고 URL : https://stackoverflow.com/questions/46214740/ios-11-iphone-x-simulator-uitabbar-icons-and-titles-being-rendered-on-top-coveri

반응형