我有一个水平滚动视图,我想以编程方式设置位置。这是视图的主体:
let radius = CGFloat(25)
let scrollWidth = CGFloat(700)
let scrollHeight = CGFloat(100)
let spacing = CGFloat(20)
let circleDiameter = CGFloat(50)
...
var body: some View {
GeometryReader { viewGeometry in
ScrollView () {
VStack(spacing: 0) {
Spacer(minLength: spacing)
Circle()
.fill(Color.black.opacity(0.5))
.scaledToFit()
.frame(width: circleDiameter, height: circleDiameter)
ScrollView(.horizontal) {
Text("The quick brown fox jumps over the lazy dog. Finalmente.")
.font(Font.title)
.frame(width: scrollWidth, height: scrollHeight)
.foregroundColor(Color.white)
.background(Color.white.opacity(0.25))
}
.frame(width: viewGeometry.size.width, height: scrollHeight)
.padding([.top, .bottom], spacing)
Circle()
.fill(Color.white.opacity(0.5))
.scaledToFit()
.frame(width: circleDiameter, height: circleDiameter)
Spacer(minLength: spacing)
}
.frame(width: viewGeometry.size.width)
}
.background(Color.orange)
}
.frame(width: 324 / 2, height: spacing * 4 + circleDiameter * 2 + scrollHeight) // testing
.cornerRadius(radius)
.background(Color.black)
}
如何更改此代码,以便可以获取“快速褐狐”的当前位置并在以后恢复它?我只是想做一些像UIKit中contentOffset
一样的事情。
我可以看到GeometryReader
可能对于获取内容的当前框架有用,但是没有等效的作者。为滚动视图或文本设置.position()
或.offset()
也不会让我感到困惑。
任何帮助将不胜感激!
答案 0 :(得分:3)
我一直在研究一个解决方案,并就通过编程设置内容偏移量https://gist.github.com/jfuellert/67e91df63394d7c9b713419ed8e2beb7
发布了我的工作要点。答案 1 :(得分:1)
我弄乱了涉及一个ScrollView
和一个或多个GeometryReaders
的几种解决方案,但是最终,如果我只是忽略ScrollView
并使用{{1} }和View.offset(x:y:)
:
在通过DragGesture
的情况下,这可以通过像拖动LinearGradient
一样拖动ScrollView
或更新绑定来进行平移
Slider
为简洁起见,省略了将拖动操作限制为滚动区域的大小。该代码允许水平滚动,使用struct SliderBinding: View {
@State var position = CGFloat(0.0)
@State var dragBegin: CGFloat?
var body: some View {
VStack {
Text("\(position)")
Slider(value: $position, in: 0...400)
ZStack {
LinearGradient(gradient: Gradient(colors: [.blue, .red]) , startPoint: .leading, endPoint: .trailing)
.frame(width: 800, height: 200)
.offset(x: position - 400 / 2)
}.frame(width:400)
.gesture(DragGesture()
.onChanged { gesture in
if (dragBegin == nil) {
dragBegin = self.position
} else {
position = (dragBegin ?? 0) + gesture.translation.width
}
}
.onEnded { _ in
dragBegin = nil
}
)
}
.frame(width: 400)
}
}
而不是CGPoint
进行水平和垂直滚动。
答案 2 :(得分:0)
据我所知,使用常规的SwiftUI ScrollView,您可以通过带有proxy.frame(in.global).minY的GeometryReader获得位置(请参见下面的修改示例),但是您无法设置“ contentOffset ”。
实际上,如果您查看“调试视图层次结构”,您会注意到我们的内容视图嵌入到内部SwiftUI的其他内容视图中(滚动视图)。因此,您将相对于此内部视图而不是滚动视图进行偏移。
搜索了一段时间后,我找不到使用SwiftUI ScrollView进行操作的任何方法(我猜这将不得不等待Apple)。我能做的(用hacks)最好的方法是滚动到底部。
更新:我以前犯了一个错误,因为它在垂直滚动条上。现在已纠正。
class SGScrollViewModel: ObservableObject{
var scrollOffset:CGFloat = 0{
didSet{
print("scrollOffset: \(scrollOffset)")
}
}
}
struct ContentView: View {
public var scrollModel:SGScrollViewModel = SGScrollViewModel()
let radius = CGFloat(25)
let scrollWidth = CGFloat(700)
let scrollHeight = CGFloat(100)
let spacing = CGFloat(20)
let circleDiameter = CGFloat(50)
var body: some View {
var topMarker:CGFloat = 0
let scrollTopMarkerView = GeometryReader { proxy -> Color in
topMarker = proxy.frame(in: .global).minX
return Color.clear
}
let scrollOffsetMarkerView = GeometryReader { proxy -> Color in
self.scrollModel.scrollOffset = proxy.frame(in: .global).minX - topMarker
return Color.clear
}
return GeometryReader { viewGeometry in
ScrollView () {
VStack(spacing: 0) {
Spacer(minLength: self.spacing)
Circle()
.fill(Color.black.opacity(0.5))
.scaledToFit()
.frame(width: self.circleDiameter, height: self.circleDiameter)
scrollTopMarkerView.frame(height:0)
ScrollView(.horizontal) {
Text("The quick brown fox jumps over the lazy dog. Finally.")
.font(Font.title)
.frame(width: self.scrollWidth, height: self.scrollHeight)
.foregroundColor(Color.white)
.background(Color.white.opacity(0.25))
.background(scrollOffsetMarkerView)
}
.frame(width: viewGeometry.size.width, height: self.scrollHeight)
.padding([.top, .bottom], self.spacing)
Circle()
.fill(Color.white.opacity(0.5))
.scaledToFit()
.frame(width: self.circleDiameter, height: self.circleDiameter)
Spacer(minLength: self.spacing)
}
.frame(width: viewGeometry.size.width)
}
.background(Color.orange)
}
.frame(width: 324 / 2, height: spacing * 4 + circleDiameter * 2 + scrollHeight) // testing
.cornerRadius(radius)
.background(Color.black)
}
}