[英]Scroll to selected position in scrollview when view loads - SwiftUI
OUTLINE大纲
I have 2 views, the first (view1) contains a HStack
and an @ObservableObject
.我有 2 个视图,第一个 (view1) 包含一个
HStack
和一个@ObservableObject
。 When the user selects a row from the HStack
the @ObservableObject
is updated to the string name of the row selected.当用户从
HStack
中选择一行时,@ @ObservableObject
将更新为所选行的字符串名称。
In view2 I have the same HStack
as the first HStack
in view1.在 view2 中,我的
HStack
与 view1 中的第一个HStack
相同。 This HStack
observes @ObservableObject
and desaturates all other rows except the one that matches the @ObservableObject
.此
HStack
观察@ObservableObject
并对除与@ObservableObject
匹配的行之外的所有其他行进行去饱和处理。
PROBLEM问题
The HStack
list in view2 is wider than the page so I would like to automatically scroll to the saturated/selected row when the view appears. view2 中的
HStack
列表比页面宽,所以我想在视图出现时自动滚动到饱和/选定的行。 I'm not totally sure how to use ScrollTo
as it needs an integer and I am only storing/observing the string name.我不完全确定如何使用
ScrollTo
,因为它需要 integer 并且我只是存储/观察字符串名称。
VIEW 1查看 1
class selectedApplication: ObservableObject {
@Published var selectedApplication = "application1"
}
struct view1: View {
@ObservedObject var selectedOption = selectedApplication()
var applications = ["application1", "application2", "application3", "application4", "application5", "application6", "application7", "application8", "application9", "application10"]
var body: some View {
VStack{
ScrollView(.horizontal){
HStack{
ForEach(applications, id: \.self) { item in
Button(action: {
self.selectedOption.selectedApplication = item
}) {
VStack(alignment: .center){
Text(item)
}
}
}
}
}
}
}
}
View2:视图2:
struct View2: View {
@ObservedObject var application: selectedApplication
var applications = ["application1", "application2", "application3", "application4", "application5", "application6", "application7", "application8", "application9", "application10"]
var body: some View {
HStack{
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader{ scroll in
HStack{
ForEach(applications, id: \.self) { item in
Button(action: {
application.selectedApplication = item
}) {
Text(item)
.saturation(application.selectedApplication == item ? 1.0 : 0.05)
}
}
}
}
}
}
}
}
You can use ScrollViewReader
with the id
that's being applied in the ForEach
, so you don't actually need the row index number (although that, too, is possible to get, if you needed to, either by using enumerated
or searching the applications
array for the index of the item.您可以将
ScrollViewReader
与在ForEach
中应用的id
一起使用,因此您实际上不需要行索引号(尽管如果需要,也可以通过使用enumerated
或搜索applications
数组来获得为项目的索引。
Here's my updated code:这是我更新的代码:
struct ContentView : View {
@ObservedObject var selectedOption = SelectedApplicationState()
var body: some View {
VStack {
View1(application: selectedOption)
View2(application: selectedOption)
}
}
}
class SelectedApplicationState: ObservableObject {
@Published var selectedApplication = "application1"
var applications = ["application1", "application2", "application3", "application4", "application5", "application6", "application7", "application8", "application9", "application10"]
}
struct View1: View {
@ObservedObject var application: SelectedApplicationState
var body: some View {
VStack{
ScrollView(.horizontal){
HStack{
ForEach(application.applications, id: \.self) { item in
Button(action: {
self.application.selectedApplication = item
}) {
VStack(alignment: .center){
Text(item)
}
}
}
}
}
}
}
}
struct View2: View {
@ObservedObject var application: SelectedApplicationState
var body: some View {
HStack{
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader{ scroll in
HStack{
ForEach(application.applications, id: \.self) { item in
Button(action: {
application.selectedApplication = item
}) {
Text(item)
.saturation(application.selectedApplication == item ? 1.0 : 0.05)
}
}
}.onReceive(application.$selectedApplication) { (app) in
withAnimation {
scroll.scrollTo(app, anchor: .leading)
}
}
}
}
}
}
}
How it works:这个怎么运作:
SelectedApplicationState
(which was your selectionApplication
ObservableObject (by the way, it is common practice to capitalize your type names -- that's why I changed the name. Plus, it was confusing to have a type and a property of that type with such a similar name) and passes it to both views. SelectedApplicationState
(这是您的selectionApplication
ObservableObject (顺便说一下,将您的类型名称大写是一种常见的做法 - 这就是我更改名称的原因。另外,具有此类的类型和属性令人困惑类似的名称)并将其传递给两个视图。SelectedApplicationState
now holds the applications
array, since it was being duplicated across views anyway SelectedApplicationState
现在保存applications
数组,因为无论如何它都在视图中被复制selectedApplication
in the ObservableObject is set, triggering onReceive
in View2
selectedApplication
时,设置 ObservableObject 中的 selectedApplication,在View2
中触发onReceive
ScrollViewReader
is told to scroll to the item with the id stored in selectedApplication
, which is passed to the onReceive
closure as app
ScrollViewReader
被告知滚动到 id 存储在selectedApplication
中的项目,该项目作为app
传递给onReceive
闭包In the event that these views are on separate pages, the position of View2 will still get set correctly once it is navigated to, because onReceive
will fire on first load and set it to the correct position.如果这些视图位于不同的页面上,则 View2 的 position 在导航到后仍将正确设置,因为
onReceive
将在首次加载时触发并将其设置为正确的 position。 The only requirement is passing that instance of SelectedApplicationState
around.唯一的要求是传递
SelectedApplicationState
的实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.