UITabBarコンポーネントの周りでiPhone Xシミュレータに問題がある人はいますか?
鉱山はアイコンとタイトルを重ねてレンダリングしているようですが、何も欠落しているかどうかはわかりません。iPhone8シミュレータでも実行しました。実際のデバイスの1つは、ストーリーボード。
iPhone X:
iPhone 8
UITabBarコンポーネントの周りでiPhone Xシミュレータに問題がある人はいますか?
鉱山はアイコンとタイトルを重ねてレンダリングしているようですが、何も欠落しているかどうかはわかりません。iPhone8シミュレータでも実行しました。実際のデバイスの1つは、ストーリーボード。
iPhone X:
iPhone 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/…)のCustom Icon Size
VoidLessが提供する回答は、TabBarの問題を部分的にしか修正しません。タブバー内のレイアウトの問題を修正しますが、タブバーを非表示にするビューコントローラーを使用すると、アニメーション中にタブバーが正しくレンダリングされません(再現するには、2つのセグエがあり、1つのモーダルと1つのプッシュが最適です。セグエを交互にすると、正しく配置されていないタブバーを参照してください)。次のコードは両方の問題を修正します。よくできました。
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
}
}
}
Objective-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の下部制約にゼロ以外の定数を安全領域に設定した場合:
期待どおりに動作し始めます...
それが私が行った唯一の変更であり、なぜそれが機能するのかはわかりませんが、誰かがそうしたいと思ったら知りたいです。
何時間もAppleをののしった後、ようやくこれを理解した。
UIKitは実際にこれを処理します。シフトされたタブバー項目は、セットアップが正しくないために発生しているようです(おそらく実際のUIKitバグ)。サブクラス化や背景ビューは必要ありません。
インターフェースビルダーでも動作します。
本当にばかげているのは、上記の手順でIBが追加した制約を正確に追加した場合でも、IBのバグも実際に確認できることです。
サブクラス化されたUITabBarを使用してsafeAreaInsetsを適用することで修正:
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を検出し、ビューの高さを32px縮小して、タブバーがホームラインの上の安全な領域に表示されるようにします。
たとえば、プログラムで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ヒューマンインターフェイスガイドラインのAppleのスクリーンショットに従って表示されるはずです:https : //developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/
カスタム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に対してのみ実行しています。Appleが将来のiOSリリースでUITabBarButtonクラスの名前を変更しないという仮定に基づいています。UITabBarButtonでこれを行うのは、アップルがUITabBarに内部サブビューをさらに追加する場合に、コードを変更して調整する必要がある場合に限られます。
これが機能するかどうかを教えてください、提案や改善を受け入れる予定です!
これに対応する迅速なものを作成するのは簡単です。
viewDidAppear(animated:)
、私の中でUITabBarController
、それは罰金を働きました。ありがとう!
このチュートリアルから:
https://github.com/eggswift/ESTabBarController
タブバーの初期化後、appdelegateクラスにこの行を書き込みます
(self.tabBarController.tabBar as? ESTabBar)?.itemCustomPositioning = .fillIncludeSeparator
タブバーの問題を解決します。
問題が解決することを願っています
ありがとう
私も同様の問題がありましたが、最初は正しくレンダリングされましたがbadgeValue
、tabBarItemの1つで設定した後、レイアウトが壊れました。サブクラス化せずに機能したの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スーパービューを使用して、制約/アンカーが同じビュー階層にあることを確認し、クラッシュを回避しました。
私の理解に基づくと、これは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;
}
}
下のセーフレイアウトガイドに対してタブバーをレイアウトしていると思います。タブバーはiPhone Xのホームラインの上に安全にタブバーアイテムを配置するために独自の計算を行うため、これはおそらく望んでいることではありません。スーパービューの下部に対して下部の制約を設定してください。iPhone Xや他のiPhoneでも正しくレイアウトされるはずです。