Я создаю индикатор загрузки в SwiftUI, который всегда должен располагаться по центру в представлении верхнего уровня иерархии представлений (т.е. по центру всего экрана в полноэкранном приложении). Это было бы легко в UIKit, но SwiftUI центрирует представления относительно их родительского представления, и я не могу получить позиции родительских представлений родительского представления.
К сожалению, мое приложение не полностью основано на SwiftUI, поэтому я не могу легко установить свойства в моих root представлениях, к которым я мог бы получить доступ в моем представлении загрузки - мне нужно, чтобы это представление было центрировано независимо от того, как выглядит иерархия представлений (смешанные родительские представления UIKit - SwiftUI). Вот почему ответы типа SwiftUI set position to center of different view не работают для моего варианта использования, поскольку в этом примере вам нужно изменить представление, в котором вы хотите центрировать свое дочернее представление.
Я пробовал поиграть с функциями .offset
и .position
из View
, однако мне не удалось получить правильные входные данные, чтобы всегда динамически центрировать мой loadingView
независимо от размера экрана или независимо от какая часть всего экрана rootView
занимает.
Пожалуйста, найдите минимально воспроизводимый пример проблемы ниже:
/// Loading view that should always be centered in the whole screen on the XY axis and should be the top view in the Z axis
struct CenteredLoadingView<RootView: View>: View {
private let rootView: RootView
init(rootView: RootView) {
self.rootView = rootView
}
var body: some View {
ZStack {
rootView
loadingView
}
// Ensure that `AnimatedLoadingView` is displayed above all other views, whose `zIndex` would be higher than `rootView`'s by default
.zIndex(.infinity)
}
private var loadingView: some View {
VStack {
Color.white
.frame(width: 48, height: 72)
Text("Loading")
.foregroundColor(.white)
}
.frame(width: 142, height: 142)
.background(Color.primary.opacity(0.7))
.cornerRadius(10)
}
}
Вид, над которым должен отображаться вид загрузки:
struct CenterView: View {
var body: some View {
return VStack {
Color.gray
HStack {
CenteredLoadingView(rootView: list)
otherList
}
}
}
var list: some View {
List {
ForEach(1..<6) {
Text($0.description)
}
}
}
var otherList: some View {
List {
ForEach(6..<11) {
Text($0.description)
}
}
}
}
Вот как выглядит результат: 
This is how the UI should look like:
желаемый UI
Я попытался изменить body
из CenteredLoadingView
, используя GeometryReader
и .frame(in: .global)
, чтобы получить глобальный размер экрана, но я добился того, что теперь мой loadingView
вообще не отображается.
var body: some View {
GeometryReader<AnyView> { geo in
let screen = geo.frame(in: .global)
let stack = ZStack {
self.rootView
self.loadingView
.position(x: screen.midX, y: screen.midY)
// Offset doesn't work either
//.offset(x: -screen.origin.x, y: -screen.origin.y)
}
// Ensure that `AnimatedLoadingView` is displayed above all other views, whose `zIndex` would be higher than `rootView`'s by default
.zIndex(.infinity)
return AnyView(stack)
}
}