У меня есть базовое представление вкладок, содержащее фотографии. Когда я добавляю стиль просмотра вкладок страницы или любой стиль к представлению вкладок, изображение дрожит при перетаскивании вниз. Если я удалю модификатор стиля представления вкладки, дрожание исчезнет при перетаскивании представления. Как исправить этот дефект, чтобы не было дрожания изображения при перетаскивании? Я использовал несколько библиотек рендеринга изображений, чтобы убедиться, что проблема связана с представлением вкладок, а не с изображением.
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
}
}
Вы используете 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)
}
}