UITabBar 구성 요소와 관련하여 iPhone X 시뮬레이터에 문제가 있습니까?
내 아이콘과 제목을 서로 렌더링하는 것처럼 보입니다. 내가 빠진 것이 확실하지 않은 경우 iPhone 8 시뮬레이터에서 실행 한 것과 실제 장치가 그림과 같이 잘 보입니다. 스토리 보드.
아이폰 X :
아이폰 8
UITabBar 구성 요소와 관련하여 iPhone X 시뮬레이터에 문제가 있습니까?
내 아이콘과 제목을 서로 렌더링하는 것처럼 보입니다. 내가 빠진 것이 확실하지 않은 경우 iPhone 8 시뮬레이터에서 실행 한 것과 실제 장치가 그림과 같이 잘 보입니다. 스토리 보드.
아이폰 X :
아이폰 8
답변:
viewDidLayoutSubviews의 UITabBar에서 invalidateIntrinsicContentSize를 호출하여 문제를 해결할 수있었습니다.
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self.tabBar invalidateIntrinsicContentSize];
}
참고 : 탭 막대의 아래쪽은 안전 영역이 아니라 기본보기의 아래쪽에 포함되어야하며 탭 막대에는 높이 제한이 없어야합니다.
[self.view layoutIfNeeded]
.
landscapeImage
탭 막대 버튼 의 속성으로 설정할 수있는 더 작은 이미지를 가져야하는 소형 탭 막대를 사용 합니다. 권장 크기는 사용자 정의 아이콘 크기 의 [Apple HIG 's] ( developer.apple.com/design/human-interface-guidelines/ios/… )에 있습니다.
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
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
}
}
나는 같은 문제가 있었다.
UITabBar의 하단 제약 조건에서 0이 아닌 상수를 안전 영역으로 설정하면 :
예상대로 작동하기 시작합니다 ...
그것이 내가 한 유일한 변화이며 그것이 왜 효과가 있는지 전혀 알지 못하지만 누군가가 알고 싶다면 알고 싶습니다.
나는 마침내 애플을 저주 한 몇 시간 후에 이것을 알아 냈다.
UIKit은 실제로 이것을 처리하며 변경된 탭 막대 항목은 잘못된 설정 (및 실제 UIKit 버그)으로 인한 것으로 보입니다. 서브 클래 싱 또는 백그라운드 뷰가 필요하지 않습니다.
심지어 인터페이스 빌더에서도 작동합니다.
정말 멍청한 것은 IB가 위의 단계에서 추가하는 정확한 제약 조건을 추가하더라도 IB의 버그를 실제로 볼 수 있다는 것입니다!
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
}
}
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의 스크린 샷에 따라 표시되어야합니다.
사용자 정의 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);
}
kPhoneXTabBarHeight
무엇입니까?
오늘은 스토리 보드의 뷰 컨트롤러에 UITabBar를 수동으로 추가 하여이 문제가 발생했습니다. 안전 영역의 바닥에 상수 0을 맞추면 문제가 발생하지만 1로 변경하면 문제가 해결됩니다. UITabBar를 평소보다 1 픽셀 높이면 응용 프로그램에서 사용할 수있었습니다.
나는이 문제에 대해 머리를 긁었다. tabBar가 초기화되고 계층 구조를보기 위해 추가되는 방법과 관련이있는 것 같습니다. 또한 호출 invalidateIntrinsicContentSize
, 프레임 설정 및 bottomInsets
UITabBar 하위 클래스 내부 와 같은 솔루션을 시도했습니다 . 그러나 일시적으로 작동하는 것처럼 보이며 다른 시나리오를 위반하거나 모호한 레이아웃 문제를 일으켜 탭 표시 줄을 되돌립니다. 문제를 디버깅 할 때 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];
}];
}
}
가정 : 나는 현재 다른 장치에서 재생산되지 않기 때문에 iPhone X에서만이 작업을 수행하고 있습니다. 향후 iOS 릴리스에서 Apple이 UITabBarButton 클래스의 이름을 변경하지 않는다는 가정을 기반으로합니다. Apple이 UITabBar에 더 많은 내부 하위 뷰를 추가하는 경우 조정하기 위해 코드를 수정해야 할 때만 UITabBarButton 에서이 작업을 수행합니다.
이것이 작동하는지 알고 lemme하시기 바랍니다 제안 및 개선에 공개됩니다!
이에 대한 신속한 대응 물을 작성하는 것은 간단해야합니다.
viewDidAppear(animated:)
내 안에 넣고 UITabBarController
잘 작동했다. 감사!
이 튜토리얼에서 :
https://github.com/eggswift/ESTabBarController
appdelegate 클래스 에서이 줄을 쓰는 탭 막대를 초기화 한 후
(self.tabBarController.tabBar as? ESTabBar)?.itemCustomPositioning = .fillIncludeSeparator
탭 막대의 내 문제를 해결합니다.
그것이 당신의 문제를 해결하기를 바랍니다.
감사
비슷한 문제가 있었는데 처음에는 올바르게 렌더링되었지만 badgeValue
tabBarItem 중 하나를 설정 하면 레이아웃이 깨졌습니다. 서브 클래 싱없이 저에게 도움 UITabBar
이 된 것은 이미 작성된 UITabBarController
서브 클래스입니다.
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
NSLayoutYAxisAnchor *tabBarBottomAnchor = self.tabBar.bottomAnchor;
NSLayoutYAxisAnchor *tabBarSuperviewBottomAnchor = self.tabBar.superview.bottomAnchor;
[tabBarBottomAnchor constraintEqualToAnchor:tabBarSuperviewBottomAnchor].active = YES;
[self.view layoutIfNeeded];
}
tabBar superview를 사용하여 구속 조건 / 앵커가 동일한 뷰 계층 구조에 있는지 확인하고 충돌을 피했습니다.
내 이해에 따르면, 이것은 UIKit 버그 인 것처럼 보이므로 자동 레이아웃 엔진이 탭 막대를 다시 올바르게 레이아웃 할 수 있도록 탭 막대 제약 조건을 다시 작성 / 재설정해야합니다.
탭 막대에 대한 높이 제한이 있으면 제거하십시오.
같은 문제에 직면하여 이것을 제거하면 문제가 해결되었습니다.
스토리 보드에서 새 UITabBarController를 만들고 모든 뷰 컨트롤러를이 새 UITabBarConttoller로 푸시했습니다. 따라서 iPhone X 시뮬레이터에서 모두 잘 작동합니다.
iPhone의 경우 서브 클래스 UITabBarController를 수행 할 수 있습니다.
class MyTabBarController: UITabBarController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 11, *) {
self.tabBar.heightAnchor.constraint(equalToConstant: 40).isActive = true
self.tabBar.invalidateIntrinsicContentSize()
}
}
}
스토리 보드로 이동하여 안전 영역 레이아웃 안내서 사용을 허용 하고 UITabbarController 클래스를 MyTabBarController 로 변경 하십시오.
PS이 솔루션은 범용 응용 프로그램 및 iPad의 경우 테스트되지 않았습니다.
@ 3x 크기의 스플래시 화면을 변경하려고합니다 (3726 × 6624)
UITabBarController
프로그래밍 방식으로 전체를 쓰는 사람들의 UITabBarItem.appearance().titlePositionAdjustment
경우 제목 위치를 조정하는 데 사용할 수 있습니다
따라서이 경우 아이콘과 제목 사이에 간격을 추가하려면 다음에서 사용하십시오 viewDidLoad
.
override func viewDidLoad() {
super.viewDidLoad()
// Specify amount to offset a position, positive for right or down, negative for left or up
let verticalUIOffset = UIOffset(horizontal: 0, vertical: hasTopNotch() ? 5 : 0)
UITabBarItem.appearance().titlePositionAdjustment = verticalUIOffset
}
장치에 노치 화면이 있는지 감지 :
func hasTopNotch() -> Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
나는 이것이 iPhoneX의 버그 UIKit이라고 생각합니다. 그것이 작동하기 때문에 :
if (@available(iOS 11.0, *)) {
if ([UIApplication sharedApplication].keyWindow.safeAreaInsets.top > 0.0) {
self.tabBarBottomLayoutConstraint.constant = 1.0;
}
}
하단 안전 레이아웃 가이드에 대해 탭 막대를 배치 할 수 있다고 생각합니다. 이 탭 표시 줄이 아이폰 X에서의 홈 라인의 상단에 안전하게 탭 표시 줄 항목의 위치를 자신의 계산을 할 것으로 보인다 않기 때문에 당신이 원하는 아마없는 설정 수퍼 아래에 대 한 수익 제약 . iPhone X 뿐만 아니라 다른 iPhone에서도 올바르게 배치됩니다 .