swiftui
Using a SwiftUI list is a convenient way to use all the auto-mechanisms to insert, remove, or move rows.
使用SwiftUI列表是使用所有自动机制插入,删除或移动行的便捷方法。
However, if you add a new entry, there is no official way to scroll to the bottom of the list where the new entry was added. So, I tried to find a solution. You’ll find a couple of questions on Stack Overflow but no real nice solution (I did not want to replace the list with a wrapped UITableView).
但是,如果添加新条目,则没有官方方法滚动到添加新条目的列表底部。 因此,我试图找到一种解决方案。 您会在Stack Overflow上找到几个问题,但没有一个真正好的解决方案(我不想用包装好的UITableView替换列表)。
By chance, I found a library called Introspect that gives access to most of the UIKit stuff behind the SwiftUI elements.
偶然地,我发现了一个名为Introspect的库,该库可以访问SwiftUI元素后面的大多数UIKit内容。
My idea was now to get access to the UITableView behind a list and then to just use a custom function named scrollToBottom
.
我的想法是现在可以访问列表后面的UITableView,然后仅使用一个名为scrollToBottom
的自定义函数。
幸福之路 (The Way to Happiness)
- Add Introspect to your project’s package list. 将Introspect添加到项目的软件包列表中。
- Import Introspect to your custom ContentView. 将Introspect导入您的自定义ContentView。
Add this to the action of your
Add
button:将此添加到“
Add
按钮的操作中:
self.tableView?.scrollToBottom(animated: true, yOffset: self.$yOffset)
- To have the compiler accept this, we need a state variable: 为了使编译器接受此条件,我们需要一个状态变量:
@State var yOffset: CGFloat = 0
- And another one: 还有一个:
@State var tableView: UITableView?
- Add this modifier to your list: 将此修饰符添加到您的列表中:
.introspectTableView(customize: { tableView in
if self.tableView == nil { self.tableView = tableView }
else { self.tableView?.setContentOffset(CGPoint(x: 0, y: self.yOffset + 60), animated: true) } })
- Add this extension: 添加此扩展名:
extension UITableView {
func scrollToBottom(animated: Bool, yOffset: Binding<CGFloat>) {
let y = contentSize.height — frame.size.height
if y < 0 { return }
yOffset.wrappedValue = y
}}
一些注意事项 (Some notes)
The addition in the third bullet triggers the scrolling to the current
yOffset
.第三个项目符号中的添加触发滚动到当前
yOffset
。The variable in the fifth bullet is needed to make the
tableView
available throughout theCustomView
, as it seems to stay constant during its lifetime.需要使用第五个项目符号中的变量,以使
tableView
在整个CustomView
可用,因为它在其生命周期内似乎保持不变。The modifier in the sixth bullet is the magic sauce. Through Introspect, we get access to the UITableView behind the list. We use the
yOffset
to adjust the content offset. For whatever reason, it’s necessary to add some offset to the offset (here: 60) because — at least in my environment — the last row is otherwise not visible or fully visible.第六个项目符号中的修饰符是魔术酱。 通过Introspect,我们可以访问列表后面的UITableView。 我们使用
yOffset
来调整内容偏移量。 无论出于何种原因,都必须在偏移量上添加一些偏移量(此处为60),因为至少在我的环境中,否则最后一行不可见或完全不可见。In the seventh bullet, the new
yOffset
is set. Because of the@State
property wrapper, the view updates according to the new offset.在第七个项目符号中,设置了新的
yOffset
。 由于@State
属性包装器,该视图根据新的偏移量进行更新。
Now, everything’s working pretty smoothly (not perfectly, but in an acceptable way). Well, not everything: If you remove a row, the positioning goes wonky (i.e. to the last save position in yOffset
).
现在,一切工作都非常顺利(不是很完美,但是可以接受)。 好吧,不是所有内容:如果删除一行,则定位yOffset
(即到yOffset
的最后一个保存位置)。
What shall we do now?
我们现在干什么?
Let’s change the
yOffset
declaration to aCGFLoat?
(an optional).让我们将
yOffset
声明更改为CGFLoat?
(可选)。In the
.onDelete(perform:)
event of the list, add aself.yOffset = nil
after the removal operation.在列表的
.onDelete(perform:)
事件中,在删除操作之后添加self.yOffset = nil
。In the
.introspectTableView
view modifier, add aguard let yOffset = self.yOffset else { return }
before the call ofsetContentOffset
.在
.introspectTableView
视图修饰符中,在调用setContentOffset
之前添加一个guard let yOffset = self.yOffset else { return }
的guard let yOffset = self.yOffset else { return }
。
Now, things are going smoothly.
现在,一切进展顺利。
结论 (Conclusion)
I added a gist on GitHub where you can check out the full code of the view. It refers to some model-related protocols that are not provided. You can just replace the model-related calls with your code.
我在GitHub上添加了要点 ,您可以在其中查看视图的完整代码。 它指的是一些未提供的与模型相关的协议。 您可以只用代码替换与模型相关的调用。
Thanks for reading!
谢谢阅读!
翻译自: https://medium.com/better-programming/swiftui-scrolling-a-list-to-the-bottom-68337e4d8db0
swiftui