SwiftUI - Использование GeometryReader без изменения размера представления - PullRequest
1 голос
/ 02 июля 2019

У меня есть заголовок, который расширяет свой фон, чтобы быть под строкой состояния, используя edgesIgnoringSafeArea. Чтобы правильно выровнять содержимое / подпредставления представления заголовка, мне нужен safeAreaInsets из GeometryReader. Однако при использовании GeometryReader мой вид больше не имеет подогнанного размера.

Код без использования GeometryReader

struct MyView : View {
    var body: some View {
        VStack(alignment: .leading) {
            CustomView()
        }
        .padding(.horizontal)
        .padding(.bottom, 64)
        .background(Color.blue)
    }
}

Preview

Expected

Код с использованием GeometryReader

struct MyView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .leading) {
                CustomView()
            }
            .padding(.horizontal)
            .padding(.top, geometry.safeAreaInsets.top)
            .padding(.bottom, 64)
            .background(Color.blue)
            .fixedSize()
        }
    }
}

Preview

enter image description here

Есть ли способ использовать GeometryReader без изменения размера основного вида?

Ответы [ 2 ]

2 голосов
/ 03 июля 2019

Я попробовал с previewLayout, и я понимаю, что вы имеете в виду. Тем не менее, я думаю, что поведение соответствует ожиданиям. Определение .sizeThatFits:

Установите контейнер (A) в размер предварительного просмотра (B), когда предлагается размер устройства (C), на котором запущен предварительный просмотр.

Я вставил несколько букв, чтобы определить каждую часть и сделать ее более понятной:

A = конечный размер предварительного просмотра.

B = Размер того, что вы изменяете с помощью .previewLayout (). В первом случае это VStack. Но во втором случае это GeometryReader.

C = Размер экрана устройства.

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

Возможно, если вы отредактируете свой вопрос, чтобы точно объяснить, чего бы вы хотели достичь, я могу немного уточнить свой ответ.

Если вы хотите, чтобы GeometryReader сообщал о размере VStack. Вы можете сделать это, поместив его в модификатор .background. Но опять же, я не уверен, какова цель, так что, возможно, это не пойдет.

Я написал статью о различном использовании GeometryReader. Вот ссылка на случай, если это поможет: https://swiftui -lab.com / geometryreader-to-the-rescue /


UPDATE

Хорошо, с вашим дополнительным объяснением, у вас есть рабочее решение. Обратите внимание, что предварительный просмотр не будет работать, потому что safeInsets сообщается как ноль. На симуляторе, однако, работает нормально:

Как вы увидите, я использую настройки просмотра. Они нигде не объясняются, но я сейчас пишу о них статью, которую скоро опубликую.

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

enter image description here

import SwiftUI

struct InsetPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0

    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }

    typealias Value = CGFloat
}

struct InsetGetter: View {
    var body: some View {
        GeometryReader { geometry in
            return Rectangle().preference(key: InsetPreferenceKey.self, value: geometry.safeAreaInsets.top)
        }
    }
}

struct ContentView : View {
    var body: some View {
        MyView()

    }
}

struct MyView : View {
    @State private var topInset: CGFloat = 0

    var body: some View {

        VStack {
            CustomView(inset: topInset)
                .padding(.horizontal)
                .padding(.bottom, 64)
                .padding(.top, topInset)
                .background(Color.blue)
                .background(InsetGetter())
                .edgesIgnoringSafeArea(.all)
                .onPreferenceChange(InsetPreferenceKey.self) { self.topInset = $0 }

            Spacer()
        }

    }
}

struct CustomView: View {
    let inset: CGFloat

    var body: some View {
        VStack {
            HStack {
                Text("C \(inset)").color(.white).fontWeight(.bold).font(.title)
                Spacer()
            }

            HStack {
                Text("A").color(.white)
                Text("B").color(.white)
                Spacer()
            }
        }

    }
}
0 голосов
/ 05 июля 2019

Мне удалось решить эту проблему, обернув главный вид страницы внутри GeometryReader и передать safeAreaInsets в MyView. Так как это основной просмотр страницы, где мы хотим, чтобы весь экран был таким, то вполне нормально быть настолько жадным, насколько это возможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...