问题
Can someone explain the behavior of this ScrollView test code -- why I can't scroll to the left and top edges, and why I can scroll beyond the right and bottom edges? And how to fix this. (Note that if we remove VStack
the behavior does not change.)
var body: some View {
ScrollView.init([.vertical,.horizontal]) {
VStack {
Text("AAA")
.padding(8)
.frame(width: 1024, height: 1024)
.background(Color.orange)
.border(Color.red)
}
}
.border(Color.blue)
}
In this image is as far to the left and up as I can scroll -- it doesn't scroll to the edges:
But here I can scroll beyond the bottom and right edges:
回答1:
I have adapted @Asperi's answer to another question (SwiftUI How to align a view that's larger than screen width), and this works.
@State private var offset : CGPoint = .zero
var body: some View {
ScrollView.init([.vertical,.horizontal]) {
VStack {
Text("AAA")
.padding(8)
.frame(width: 1024, height: 1024)
.background(Color.orange)
.border(Color.red)
}
.background(rectReader())
.offset(x: self.offset.x, y: self.offset.y)
}
.border(Color.blue)
}
func rectReader() -> some View {
return GeometryReader { (geometry) -> AnyView in
let offset : CGPoint = CGPoint.init(
x: -geometry.frame(in: .global).minX,
y: -geometry.frame(in: .global).minY
)
if self.offset == .zero {
DispatchQueue.main.async {
self.offset = offset
}
}
return AnyView(Rectangle().fill(Color.clear))
}
}
回答2:
Or you can try to use one ScrollView for each direction, try this
import SwiftUI
struct ContentView: View {
var body: some View {
ScrollView(.horizontal, showsIndicators: true) {
ScrollView(.vertical, showsIndicators: true) {
Color.yellow.frame(width: 1024, height: 1024)
.overlay(Text("A").font(.largeTitle), alignment: .topLeading)
.overlay(Text("B").font(.largeTitle), alignment: .topTrailing)
.overlay(Text("C").font(.largeTitle), alignment: .bottomTrailing)
.overlay(Text("D").font(.largeTitle), alignment: .bottomLeading)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
UPDATE
to be able to see, what happens using .offset modifier, try imagine the result of this snippet
import SwiftUI
struct ContentView: View {
var body: some View {
HStack {
Text("Hello").padding().background(Color.yellow).offset(x: 20, y: 40).border(Color.red)
Text("World").padding().background(Color.pink).offset(x: -10, y: -10).border(Color.yellow)
}.padding().border(Color.gray)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
回答3:
I came across this question and answers as I was today looking for a solution of this "content view miss-placement problem" for many hours as I'm trying to scroll a (zoomed) image in any direction.
Neither of the solutions proposed here are "nice" or applicable in my case. But after finding a solution for myself, I want to document here how I would solve your problem.
The main problem is that the center of your content view (=VStack
with Text
element) is aligned with the center of the ScrollView
. This is always the case: whether the content size is smaller or bigger than the ScrollView
size. (Remember: The ScrollView
size corresponds to the screen size, minus safe area edge insets). To align your content views top leading edge with the scrollviews top leading edge, you will have to offset your content by the amount which it is currently overlapping on the left side.
The good thing: it can be calculated directly using the GeometryReader
and the known content size.
var body: some View {
GeometryReader { proxy -> AnyView in
let insets = proxy.safeAreaInsets
let sw = proxy.size.width + insets.leading + insets.trailing
let sh = proxy.size.height + insets.top + insets.bottom
let contentSize : CGFloat = 1024
let dx: CGFloat = (contentSize > sw ? (contentSize - sw)/2 : 0.0)
let dy: CGFloat = (contentSize > sh ? (contentSize - sh)/2 : 0.0)
return AnyView(
ScrollView([.vertical,.horizontal]) {
VStack {
Text("AAA")
.padding(8)
.frame(width: 1024, height: 1024)
.background(Color.orange)
.border(Color.red)
}
.offset(x: dx, y: dy)
}
.border(Color.blue)
)
}
}
来源:https://stackoverflow.com/questions/60570282/swiftui-scrollview-content-frame-and-offset