Стиль TabView вызывает дрожание во время жеста

У меня есть базовое представление вкладок, содержащее фотографии. Когда я добавляю стиль просмотра вкладок страницы или любой стиль к представлению вкладок, изображение дрожит при перетаскивании вниз. Если я удалю модификатор стиля представления вкладки, дрожание исчезнет при перетаскивании представления. Как исправить этот дефект, чтобы не было дрожания изображения при перетаскивании? Я использовал несколько библиотек рендеринга изображений, чтобы убедиться, что проблема связана с представлением вкладок, а не с изображением.

import SwiftUI

struct StoryViewMain: View {
    var body: some View {
        TabView {
            AsyncImage(url: URL(string: "https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?cs=srgb&dl=pexels-anjana-c-169994-674010.jpg&fm=jpg"))
                .aspectRatio(contentMode: .fill)
        }
        .tabViewStyle(.page(indexDisplayMode: .never))  // HERE ---
        .background(.black)
    }
}

struct ContentView22: View {
    @State private var offset: CGSize = .zero
    @State private var startOfDragLocation: CGPoint = .zero
    @State private var circleSize: CGFloat = .zero
    @State var backOpac = 1.0

    var body: some View {
        GeometryReader { proxy in
            let h = proxy.size.height
            ZStack {
                VStack {
                    StoryViewMain()
                        .frame(width: widthOrHeight(width: true))
                        .offset(y: -top_Inset())
                }
                .padding(.top, top_Inset())
                .padding(.bottom, bottom_Inset())
                .frame(width: widthOrHeight(width: true), height: widthOrHeight(width: false) - bottom_Inset())
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background {
                Color.black.padding(-h)
            }
            .mask(alignment: .topLeading) {
                if offset == .zero {
                    Rectangle().ignoresSafeArea()
                } else {
                    Circle()
                        .position(startOfDragLocation)
                        .frame(width: circleSize, height: circleSize)
                }
            }
            .offset(offset)
            .background(content: {
                Color.black.opacity(backOpac).ignoresSafeArea()
            })
            .simultaneousGesture(
                DragGesture(minimumDistance: 0, coordinateSpace: .local)
                    .onChanged { value in
                        if value.translation.height >= 0 {
                            if startOfDragLocation != value.startLocation {
                                startOfDragLocation = value.startLocation
                            }
                            offset = value.translation
                            let newH = h * 1.5
                            circleSize = max(100, newH - (newH * (value.translation.height / 300.0)))
                            backOpac = max(0.0, min(1.0, 1.0 - (value.translation.height / 500.0)))
                        }
                    }
                    .onEnded({ value in
                        withAnimation(.easeIn(duration: 0.15)){
                            circleSize = h + h
                            offset = CGSize(width: 0, height: 0.001)
                        }
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
                            offset = .zero
                        }
                    })
            )
        }
    }
}

#Preview(body: {
    ContentView22()
})

func widthOrHeight(width: Bool) -> CGFloat {
    let scenes = UIApplication.shared.connectedScenes
    let windowScene = scenes.first as? UIWindowScene
    let window = windowScene?.windows.first
    
    if width {
        return window?.screen.bounds.width ?? 0
    } else {
        return window?.screen.bounds.height ?? 0
    }
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы используете AsyncImage внутри ZStack, размер которого автоматически соответствует размеру его родителя. Поэтому вам нужно обновить размер (maxWidth, maxHeight) после того, как изображение появится со знаком GeometryReader. Вот решение:

struct StoryViewMain: View {
    @State var sizeOnLoaded: CGSize? = nil // Will update on AsyncImage.appear
    var body: some View {
        TabView {
            ZStack(content: {
                GeometryReader(content: { geometry in
                    AsyncImage(url: URL(string: "https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?cs=srgb&dl=pexels-anjana-c-169994-674010.jpg&fm=jpg"), content: {
                        phase in
                        if let image = phase.image {
                            image
                            .resizable(resizingMode: .stretch)
                            .scaledToFill()
                            
                        } else {
                            Color.black
                        }
                    })
                    .frame( // constraint the size here ---
                        maxWidth: sizeOnLoaded?.width ?? .infinity,
                        maxHeight: sizeOnLoaded?.height ?? .infinity
                    )
                    .onAppear(perform: {
                        sizeOnLoaded = geometry.size // --- Fix the size
                    })
                })
            })
        }
        .tabViewStyle(.page(indexDisplayMode: .never))  // HERE ---
        .background(.black)
    }
}

Другие вопросы по теме