SwiftUI 使用 Swift 结构和 ID 时让 ScrollViewReader 滚动
SwiftUI getting ScrollViewReader to scroll when using Swift structures and id's
我有几个简单的 Swift UI 屏幕结构的所有 运行。该结构定义了一个小部件的视图、它的名称和它进入的顺序。我正在尝试制作一个水平列表,其中每个按钮在按下时都会在滚动视图中居中。这就是我想要做的:
我遇到的问题是我无法让 ScrollViewReader 将 scoll 视图移动到正确的位置。它认为这与 ids 有关,但我不确定。我是 SwiftUI 的新手,这可能是一个非常基本的问题,但非常感谢您的帮助!
这是我的结构
struct WidgetView: Identifiable, Hashable{
static func == (lhs: WidgetView, rhs: WidgetView) -> Bool {
return lhs.id == rhs.id && lhs.friendlyName == rhs.friendlyName && lhs.order == rhs.order && lhs.selected == rhs.selected
}
let id = UUID()
var friendlyName: String
var view: Any
var order: Int
var selected: Bool
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
extension WidgetView {
static var data: [WidgetView] {
[
WidgetView(friendlyName: "News", view: MusicView(), order: 1, selected: false),
WidgetView(friendlyName: "Music", view: MusicView(), order: 2, selected: false),
WidgetView(friendlyName: "Ambiance", view: AmbianceView(), order: 3, selected: true),
WidgetView(friendlyName: "Weather", view: WeatherView(), order: 4, selected: false),
WidgetView(friendlyName: "Routines", view: MusicView(), order: 5, selected: false)
]
}
}
这是我的两个 SwiftUI 视图,第一个只是小文本框,第二个是滚动视图,但无法正常工作。
struct WidgetName: View {
let widget: WidgetView
var body: some View {
ZStack(alignment: .center) {
Color.clear
Button(action: {
print("Hello")
}){
ZStack{
Text(widget.friendlyName)
.fontWeight(.semibold)
.opacity(0)
.padding(widget.selected ? 15: 12)
.overlay(
RoundedRectangle(cornerRadius: 15)
.fill(Color.white)
.opacity(widget.selected ? 1: 0.5)
)
Text(widget.friendlyName)
.fontWeight(.semibold)
.foregroundColor(.black)
.opacity(widget.selected ? 1: 0.5)
}
}
}.padding()
}
}
struct WidgetName_Previews: PreviewProvider {
static var previews: some View {
WidgetName(widget: WidgetView.data[1])
.previewLayout(.fixed(width: 400, height: 60))
.background(Color.purple)
WidgetName(widget: WidgetView.data[2])
.previewLayout(.fixed(width: 400, height: 60))
.background(Color.purple)
WidgetName(widget: WidgetView.data[3])
.previewLayout(.fixed(width: 400, height: 60))
.background(Color.purple)
}
}
struct WidgetNameStrip: View {
var widgets: [WidgetView]
var body: some View {
VStack{
Spacer()
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { value in
Button("Jump to #32") {
value.scrollTo(3)
}
.foregroundColor(.white)
HStack(spacing: 10) {
ForEach(widgets, id: \.self) { widget in
WidgetName(widget: widget)
}
}
}
}
.frame(height: 80)
}
}
}
struct WidgetNameStrip_Previews: PreviewProvider {
static var previews: some View {
WidgetNameStrip(widgets: WidgetView.data)
.background(Color.purple)
.previewDevice("iPhone 8")
}
}
对于您的代码,正如我所见,它需要使用 order
作为视图的 id,因为 scrollTo
使用 id/s 来查找视图,即:
Button("Jump to #32") {
value.scrollTo(3)
}
.foregroundColor(.white)
HStack(spacing: 10) {
ForEach(widgets, id: \.self) { widget in
WidgetName(widget: widget)
.id(widget.order) // << here !!
}
}
根据@Asperi 的回复,您还可以在建立 id 后在 .scrollTo 上使用锚参数。
锚点控制滚动视图中所选项目在滚动视图中的位置。
Button("Jump to #32") {
value.scrollTo(id, anchor: .center)
}
您可以使用 withAnimation
对其进行动画处理
withAnimation { value.scrollTo(3, anchor: .center) }
我有几个简单的 Swift UI 屏幕结构的所有 运行。该结构定义了一个小部件的视图、它的名称和它进入的顺序。我正在尝试制作一个水平列表,其中每个按钮在按下时都会在滚动视图中居中。这就是我想要做的:
我遇到的问题是我无法让 ScrollViewReader 将 scoll 视图移动到正确的位置。它认为这与 ids 有关,但我不确定。我是 SwiftUI 的新手,这可能是一个非常基本的问题,但非常感谢您的帮助!
这是我的结构
struct WidgetView: Identifiable, Hashable{
static func == (lhs: WidgetView, rhs: WidgetView) -> Bool {
return lhs.id == rhs.id && lhs.friendlyName == rhs.friendlyName && lhs.order == rhs.order && lhs.selected == rhs.selected
}
let id = UUID()
var friendlyName: String
var view: Any
var order: Int
var selected: Bool
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
extension WidgetView {
static var data: [WidgetView] {
[
WidgetView(friendlyName: "News", view: MusicView(), order: 1, selected: false),
WidgetView(friendlyName: "Music", view: MusicView(), order: 2, selected: false),
WidgetView(friendlyName: "Ambiance", view: AmbianceView(), order: 3, selected: true),
WidgetView(friendlyName: "Weather", view: WeatherView(), order: 4, selected: false),
WidgetView(friendlyName: "Routines", view: MusicView(), order: 5, selected: false)
]
}
}
这是我的两个 SwiftUI 视图,第一个只是小文本框,第二个是滚动视图,但无法正常工作。
struct WidgetName: View {
let widget: WidgetView
var body: some View {
ZStack(alignment: .center) {
Color.clear
Button(action: {
print("Hello")
}){
ZStack{
Text(widget.friendlyName)
.fontWeight(.semibold)
.opacity(0)
.padding(widget.selected ? 15: 12)
.overlay(
RoundedRectangle(cornerRadius: 15)
.fill(Color.white)
.opacity(widget.selected ? 1: 0.5)
)
Text(widget.friendlyName)
.fontWeight(.semibold)
.foregroundColor(.black)
.opacity(widget.selected ? 1: 0.5)
}
}
}.padding()
}
}
struct WidgetName_Previews: PreviewProvider {
static var previews: some View {
WidgetName(widget: WidgetView.data[1])
.previewLayout(.fixed(width: 400, height: 60))
.background(Color.purple)
WidgetName(widget: WidgetView.data[2])
.previewLayout(.fixed(width: 400, height: 60))
.background(Color.purple)
WidgetName(widget: WidgetView.data[3])
.previewLayout(.fixed(width: 400, height: 60))
.background(Color.purple)
}
}
struct WidgetNameStrip: View {
var widgets: [WidgetView]
var body: some View {
VStack{
Spacer()
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { value in
Button("Jump to #32") {
value.scrollTo(3)
}
.foregroundColor(.white)
HStack(spacing: 10) {
ForEach(widgets, id: \.self) { widget in
WidgetName(widget: widget)
}
}
}
}
.frame(height: 80)
}
}
}
struct WidgetNameStrip_Previews: PreviewProvider {
static var previews: some View {
WidgetNameStrip(widgets: WidgetView.data)
.background(Color.purple)
.previewDevice("iPhone 8")
}
}
对于您的代码,正如我所见,它需要使用 order
作为视图的 id,因为 scrollTo
使用 id/s 来查找视图,即:
Button("Jump to #32") {
value.scrollTo(3)
}
.foregroundColor(.white)
HStack(spacing: 10) {
ForEach(widgets, id: \.self) { widget in
WidgetName(widget: widget)
.id(widget.order) // << here !!
}
}
根据@Asperi 的回复,您还可以在建立 id 后在 .scrollTo 上使用锚参数。
锚点控制滚动视图中所选项目在滚动视图中的位置。
Button("Jump to #32") {
value.scrollTo(id, anchor: .center)
}
您可以使用 withAnimation
对其进行动画处理withAnimation { value.scrollTo(3, anchor: .center) }