FullScreenCover с динамическим размером рамки – возможно?

Вопрос или проблема

У меня есть представление, в котором я вычисляю размер изображения. Эти размеры должны быть размерами для полноэкранного покрытия. Проблема в том, что переменная @State не изменила значение, когда я присвоил ей новое значение.

Я что-то читал, и, возможно, переменная @State не подходит для этого. Но что еще я могу сделать, чтобы достичь своей цели.

struct ExerciseDetailTopViewiPad: View {
    
    let exercise: ExerciseData
    
    @State private var showExerciseImageViewer = false
    @State private var maxWidth: CGFloat = 533
    @State private var maxHeight: CGFloat = 850
    
    var body: some View {
    
        Image(uiImage: exercise.exerciseImage.imageExerciseFromBase64)
            .onTapGesture {
                let dim: CGFloat = exercise.exerciseImage.imageExerciseFromBase64.size.height / exercise.exerciseImage.imageExerciseFromBase64.size.width
                let newWidth = maxHeight / dim - 30 // 30 высота верхнего меню
                maxWidth = newWidth.rounded(.up) // ==> ТУТ ПРОБЛЕМА - присвоение не изменило значение переменной
                showExerciseImageViewer = true
            }
            .fullScreenCover(isPresented: $showExerciseImageViewer) {
                ExerciseDetailImageVieweriPad(exercise: exercise)
                    .frame(maxWidth: maxWidth, maxHeight: maxHeight)
                    .clipShape(RoundedRectangle(cornerRadius: 10))
                    .shadow(color: Color(white: 0.7), radius: 20)
                    .presentationBackground {Rectangle().fill(.clear)}
            }
    }
}

Ответ или решение

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

Проблема

Вы сталкиваетесь с тем, что значение переменной @State (maxWidth и maxHeight) не обновляется при попытке задать новое значение в обработчике жеста нажатия (onTapGesture). Текущий подход, который использует @State, может не подойти в этой ситуации, поскольку SwiftUI требует определённой структуры для управления состоянием интерфейса.

Решение

  1. Использование оберточных свойств (Binding): Вместо изменения значений maxWidth и maxHeight напрямую в обработчике, вы можете использовать обертку Binding. Для этого объявите переменные как @State в родительской вью и передайте их через инициализатор в дочернюю вью.

  2. Использование @State для динамического размера: Проверьте, корректно ли у вас изменяются значения в вашем onTapGesture. Иногда значение может обновляться, но не инициировать повторный рендеринг пользовательского интерфейса. В таком случае, стоит использовать @ObservedObject или @EnvironmentObject, если у вас имеются данные, которые могут изменяться вне текущего View.

Пример кода

Вот как вы можете изменить ваш текущий код для более надежного обновления размеров:

struct ExerciseDetailTopViewiPad: View {

    let exercise: ExerciseData

    @State private var showExerciseImageViewer = false
    @State private var maxWidth: CGFloat = 533
    @State private var maxHeight: CGFloat = 850

    var body: some View {

        Image(uiImage: exercise.exerciseImage.imageExerciseFromBase64)
            .onTapGesture {
                let dim: CGFloat = exercise.exerciseImage.imageExerciseFromBase64.size.height /
                                exercise.exerciseImage.imageExerciseFromBase64.size.width
                let newWidth = maxHeight / dim - 30 // 30 высота верхнего меню
                maxWidth = newWidth.rounded(.up) // Изменение значения
                showExerciseImageViewer = true
            }
            .fullScreenCover(isPresented: $showExerciseImageViewer) {
                ExerciseDetailImageVieweriPad(exercise: exercise, maxWidth: maxWidth, maxHeight: maxHeight)
                    .frame(maxWidth: maxWidth, maxHeight: maxHeight)
                    .clipShape(RoundedRectangle(cornerRadius: 10))
                    .shadow(color: Color(white: 0.7), radius: 20)
                    .presentationBackground { Rectangle().fill(.clear) }
            }
    }
}

struct ExerciseDetailImageVieweriPad: View {
    let exercise: ExerciseData
    var maxWidth: CGFloat
    var maxHeight: CGFloat

    var body: some View {
        // Дизайн вашего вью для отображения изображения
        // реализуйте свой интерфейс здесь с использованием maxWidth и maxHeight
    }
}

Заключение

Очень важно помнить, что @State переменные являются внутренними состояниями для конкретного вью. Ваша проблема может заключаться в том, что система SwiftUI не отслеживает изменения в состоянии, если они происходят в пределах контекста, который не вызывает повторный рендер. Используя @Binding, @ObservedObject или передавая их напрямую через параметры, вы можете добиться нужного результата.

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

Оцените материал
Добавить комментарий

Капча загружается...