SwiftUI TabView превышает высоту, поэтому дочерние элементы не центрируются

У меня возникла проблема с реализацией TabView, и я не знаю, использую ли я ее неправильно или есть проблема в SwiftUI. Я написал небольшой образец, чтобы воспроизвести его:

import SwiftUI

@main
struct MyPlaygroundAppApp: App {
    init() {
        let toolbarAppearance = UIToolbarAppearance()
        toolbarAppearance.backgroundColor = UIColor(Color.green)
        
        UIToolbar.appearance().standardAppearance = toolbarAppearance
        UIToolbar.appearance().scrollEdgeAppearance = toolbarAppearance
        UIToolbar.appearance().compactAppearance = toolbarAppearance
        UIToolbar.appearance().compactScrollEdgeAppearance = toolbarAppearance
    }
    
    var body: some Scene {
        WindowGroup {
            PlayContentView()
        }
    }
}

import SwiftUI

struct PlayContentView: View {
    var body: some View {
        TabView {
            ContentView()
        }
        .background(Color.green)
        .edgesIgnoringSafeArea(.top)
        .tabViewStyle(.page(indexDisplayMode: .never))
    }
}

struct ContentView: View {
    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                VStack(spacing: 0) {
                    ZStack {
                        VStack(spacing: 0) {
                            Text("Title")
                            Text("Text")
                        }
                    }
                    .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: 80, alignment: .bottom)
                    .padding(.top, 12)
                    .background(Color.yellow)
                    Divider()
                        .overlay(Color.black)
                }
                
                ScrollView([.vertical, .horizontal], showsIndicators: false) {
                    VStack {
                    }
                    .frame(width: 200, height: 300)
                    .frame(maxWidth: .infinity)
                    .background(Color.gray)
                }
                .background(Color.blue)
            }
            .toolbar {
                ToolbarItem(placement: .status) {
                    Text("press me")
                }
            }
        }
    }
}

#Preview {
    PlayContentView()
}

Результат выглядит следующим образом:

Как вы можете видеть, серый прямоугольник не центрирован по вертикали, у него больше места сверху, чем снизу. Когда я меняю TabView на ZStack, пространство кажется правильным, поэтому я думаю, что проблема заключается в TabView. Я также изменил tabViewStyle на displayMode.always, а затем вижу, что внутри нижней панели появляется маленькая точка. Поэтому я думаю, что TabView имеет неправильную высоту. Когда я отключаю панель инструментов, я также вижу, что синий фон опускается вниз, а затем я также вижу, что серое поле находится по центру. Я предполагаю, что TabView неправильно обрабатывает панель инструментов. Была ли у кого-нибудь еще эта проблема раньше?


69
1

Ответ:

Решено

Причина, по которой серый квадрат не находится по центру, заключается в том, что (прокручиваемая) синяя область продолжается за панелью инструментов. Когда панель инструментов скрыта, серый квадрат располагается по центру по вертикали.

Вот два обходных пути:

1. Вместо этого прикрепите .toolbar к TabView или к NavigationStack.

Например:

NavigationStack {
    VStack(spacing: 0) {
        // ...
    }
}
.toolbar {
    // ...
}

2. Добавьте отступы под VStack.

Если панель инструментов остается прикрепленной к VStack, вы можете освободить для нее место, добавив немного нижнего поля. Однако я не смог найти способ измерить высоту панели инструментов по отображаемым компонентам, поэтому вам, возможно, придется прибегнуть к жестко запрограммированному значению.

При тестировании на симуляторе iPhone 15 с iOS 17.5 отступ должен составлять 49 пунктов, но это может измениться в будущей версии iOS. Хорошей новостью является то, что он, кажется, остается постоянным, даже когда используется больший размер текста.

NavigationStack {
    VStack(spacing: 0) {
        // ...
    }
    .padding(.bottom, 49)
    .toolbar {
        // ...
    }
}

Альтернативный подход — использовать специальную панель инструментов и разместить ее внизу VStack. Вы могли бы назвать это третьим обходным путем.

Кстати, еще один способ установить цвет фона панели инструментов — использовать .toolbarBackground вместо настройки UIToolbarAppearance в инициализации приложения. Однако это работает только для второго (и третьего) обходного пути, а не для первого:

VStack(spacing: 0) {
    // ...
}
.padding(.bottom, 49)
.toolbar {
    // ...
}
.toolbarBackground(.visible, for: .bottomBar)
.toolbarBackground(.green, for: .bottomBar)