看起来在当前的工具/系统中,刚刚发布的 Xcode 11.4/iOS 13.4 中将没有 SwiftUI 原生支持“滚动到”功能List。因此,即使他们,Apple,将在下一个主要版本中提供它,我也需要对 iOS 13.x 的向后支持。

那么我将如何以最简单和轻松的方式做到这一点?

  • 滚动列表结束
  • 滚动列表到顶部
  • 和别的

(我不喜欢像之前在 SO 上提出的那样将完整的UITableView基础设施包装起来UIViewRepresentable/UIViewControllerRepresentable)。

SWIFTUI 2.0

这是 Xcode 12 / iOS 14 (SwiftUI 2.0) 中可能的替代解决方案,当滚动控件位于滚动区域之外时,可以在同一场景中使用(因为 SwiftUI2ScrollViewReader只能在内部使用 ScrollView

注意:行内容设计不在考虑范围内

使用 Xcode 12b / iOS 14 测试

class ScrollToModel: ObservableObject {enum Action {case endcase top}@Published var direction: Action? = nil
}struct ContentView: View {@StateObject var vm = ScrollToModel()let items = (0..<200).map { $0 }var body: some View {VStack {HStack {Button(action: { vm.direction = .top }) { // < hereImage(systemName: "arrow.up.to.line").padding(.horizontal)}Button(action: { vm.direction = .end }) { // << hereImage(systemName: "arrow.down.to.line").padding(.horizontal)}}Divider()ScrollView {ScrollViewReader { sp inLazyVStack {ForEach(items, id: \.self) { item inVStack(alignment: .leading) {Text("Item \(item)").id(item)Divider()}.frame(maxWidth: .infinity).padding(.horizontal)}}.onReceive(vm.$direction) { action inguard !items.isEmpty else { return }withAnimation {switch action {case .top:sp.scrollTo(items.first!, anchor: .top)case .end:sp.scrollTo(items.last!, anchor: .bottom)default:return}}}}}}}
}

SWIFTUI 1.0+

这是一种有效的方法的简化变体,看起来很合适,并且需要几个屏幕代码。

使用 Xcode 11.2+ / iOS 13.2+ 测试(也使用 Xcode 12b / iOS 14)

使用演示:

struct ContentView: View {private let scrollingProxy = ListScrollingProxy() // proxy helpervar body: some View {VStack {HStack {Button(action: { self.scrollingProxy.scrollTo(.top) }) { // < hereImage(systemName: "arrow.up.to.line").padding(.horizontal)}Button(action: { self.scrollingProxy.scrollTo(.end) }) { // << hereImage(systemName: "arrow.down.to.line").padding(.horizontal)}}Divider()List {ForEach(0 ..< 200) { i inText("Item \(i)").background(ListScrollingHelper(proxy: self.scrollingProxy) // injection)}}}}
}

解决方案:

注入List可表示的轻视图可以访问 UIKit 的视图层次结构。当List重用行时,没有更多的值然后将行放入屏幕。

struct ListScrollingHelper: UIViewRepresentable {let proxy: ListScrollingProxy // reference typefunc makeUIView(context: Context) -> UIView {return UIView() // managed by SwiftUI, no overloads}func updateUIView(_ uiView: UIView, context: Context) {proxy.catchScrollView(for: uiView) // here UIView is in view hierarchy}
}

找到封闭UIScrollView(需要做一次)然后将所需的“滚动到”操作重定向到存储的滚动视图的简单代理

class ListScrollingProxy {enum Action {case endcase topcase point(point: CGPoint)     // << bonus !!}private var scrollView: UIScrollView?func catchScrollView(for view: UIView) {if nil == scrollView {scrollView = view.enclosingScrollView()}}func scrollTo(_ action: Action) {if let scroller = scrollView {var rect = CGRect(origin: .zero, size: CGSize(width: 1, height: 1))switch action {case .end:rect.origin.y = scroller.contentSize.height +scroller.contentInset.bottom + scroller.contentInset.top - 1case .point(let point):rect.origin.y = point.ydefault: {// default goes to top}()}scroller.scrollRectToVisible(rect, animated: true)}}
}extension UIView {func enclosingScrollView() -> UIScrollView? {var next: UIView? = selfrepeat {next = next?.superviewif let scrollview = next as? UIScrollView {return scrollview}} while next != nilreturn nil}
}

Moj*_*ini  10

只需滚动到 id:

scrollView.scrollTo(ROW-ID)

由于 SwiftUI 结构化设计的数据驱动,你应该知道你所有的项目 ID。所以,你可以滚动到任何ID与ScrollViewReader来自iOS的14,并用Xcode的12

struct ContentView: View {let items = (1...100)var body: some View {ScrollViewReader { scrollProxy inScrollView {ForEach(items, id: \.self) { Text("\($0)"); Divider() }}HStack {Button("First!") { withAnimation { scrollProxy.scrollTo(items.first!) } }Button("Any!") { withAnimation { scrollProxy.scrollTo(50) } }Button("Last!") { withAnimation { scrollProxy.scrollTo(items.last!) } }}}}
}

注意 ScrollViewReader应该支持所有可滚动的内容,但现在只支持ScrollView


预览


Lac*_*rov  8

这是一个适用于 iOS13&14 的简单解决方案:
使用Introspect。
我的情况是初始滚动位置。

ScrollView(.vertical, showsIndicators: false, content: {...}).introspectScrollView(customize: { scrollView inscrollView.scrollRectToVisible(CGRect(x: 0, y: offset, width: 100, height: 300), animated: false)})

如果需要,可以根据屏幕大小或元素本身计算高度。此解决方案适用于垂直滚动。对于水平,您应该指定 x 并将 y 保留为 0

  • 这是针对 SwiftUI 1.0 的最佳答案 (2认同)

小智  7

谢谢 Asperi,很棒的提示。当在视图之外添加新条目时,我需要向上滚动列表。重新设计以适应 macOS。

我将状态/代理变量带到环境对象并在视图外使用它来强制滚动。我发现我必须更新它两次,第二次有 0.5 秒的延迟才能获得最佳结果。第一次更新可防止视图在添加行时滚动回顶部。第二次更新滚动到最后一行。我是新手,这是我的第一个 stackoverflow 帖子:o

为 MacOS 更新:

struct ListScrollingHelper: NSViewRepresentable {let proxy: ListScrollingProxy // reference typefunc makeNSView(context: Context) -> NSView {return NSView() // managed by SwiftUI, no overloads}func updateNSView(_ nsView: NSView, context: Context) {proxy.catchScrollView(for: nsView) // here NSView is in view hierarchy}
}class ListScrollingProxy {//updated for mac osxenum Action {case endcase topcase point(point: CGPoint)     // << bonus !!}private var scrollView: NSScrollView?func catchScrollView(for view: NSView) {//if nil == scrollView { //unB - seems to lose original view when list is emptiedscrollView = view.enclosingScrollView()//}}func scrollTo(_ action: Action) {if let scroller = scrollView {var rect = CGRect(origin: .zero, size: CGSize(width: 1, height: 1))switch action {case .end:rect.origin.y = scroller.contentView.frame.minYif let documentHeight = scroller.documentView?.frame.height {rect.origin.y = documentHeight - scroller.contentSize.height}case .point(let point):rect.origin.y = point.ydefault: {// default goes to top}()}//tried animations without success :(scroller.contentView.scroll(to: NSPoint(x: rect.minX, y: rect.minY))scroller.reflectScrolledClipView(scroller.contentView)}}
}
extension NSView {func enclosingScrollView() -> NSScrollView? {var next: NSView? = selfrepeat {next = next?.superviewif let scrollview = next as? NSScrollView {return scrollview}} while next != nilreturn nil}
}

如何在 SwiftUI 中以编程方式滚动列表?相关推荐

  1. 如何在Java中以编程方式阅读,添加或删除PPT中的幻灯片便笺?

    幻灯片注释用于添加其他信息,作为演示文稿中的参考.演示者添加了这些注释,以回顾与他们的演示相关的要点.在本文中,将学习如何以编程方式操作演示文稿中的幻灯片注释.特别是,本文将介绍如何使用Java读取, ...

  2. 快速学习:如何在Java中以编程方式将PNG或JPG图像转换为PSD?

    JPG和PNG图像是一些最常用的光栅图像格式.有时可以根据需要将JPG或PNG图像转换为PSD文件格式.当要将不同的图层组合到一个文件中时,这可能会很有用.本文将介绍一下更多详细信息: 使用Java以 ...

  3. 如何在 C# 中以编程方式将 IGS/IGES 文件转换为 PDF?

    计算机辅助设计应用程序使用 IGS 文件,因为它们包含设计信息.您可以将 IGS 文件转换为 PDF 格式的文档,以便在多个操作系统和环境中查看内容. 使用 C# 以编程方式将 IGS 或 IGES ...

  4. 如何在android中设置背景,如何在Android中以编程方式设置背景可绘制

    MMTTMM layout.setBackgroundResource(R.drawable.ready);是正确的.实现它的另一种方法是使用以下方法:final int sdk = android. ...

  5. linux给文件夹图标,linux – 如何在GNOME中以编程方式设置自定义文件夹图标?

    我终于想出了如何做到这一点!这是一个在标准Gnome环境中工作的Python脚本: #!/usr/bin/env python import sys from gi.repository import ...

  6. android 闪光灯程序,如何在Android中以编程方式打开前闪光灯?

    在API 23或更高版本中(AndroidM,6.0)打开代码if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { CameraManage ...

  7. android 打开闪光灯,如何在Android中以编程方式打开前置闪光灯...

    对于这个问题,你应该: >检查手电筒是否是 可用与否? >如果是,则关闭/打开 >如果没有,那么根据你的应用,你可以做任何事情 需要. 要检查设备中闪存的可用性: 您可以使用以下内容 ...

  8. android attributeset,如何在android中以编程方式创建时传递AttributeSet

    当您的视图从xml中膨胀时,将使用具有Context和AttributeSet的构造函数.您不应该使用它来创建对象.您应该使用带有Context作为参数的构造函数. AttributeSet是接口,您 ...

  9. android关闭触摸声音,如何在Android中以编程方式禁用触摸时的振动和声音?

    我正在使用ImageView的OnLongClickListener创建一个应用程序并打开alertdialog,并且还有ontouch缩放功能.但是当我长时间按压而不是振动时,可以在长按聆听器上关闭 ...

最新文章

  1. 专家认为自动驾驶汽车需要很多年的五个原因
  2. PyTorch基于Apex的混合精度加速
  3. 提交不了_从来没有借过钱!征信空白,为什么办不了信用卡?
  4. ADSL使用注意事项
  5. 15.使用using和try/finally来做资源清理
  6. Eclipse run configrations 配置
  7. 用Python库PySimpleGUI制作自动化办公小软件
  8. 清除xcode缓存文件以及清楚mac 微信缓存
  9. 高中计算机矩阵算法ppt,高中信息技术教科版必修1 数据与计算4.2 数值计算一等奖课件ppt...
  10. x86 单线并发多拨_【转帖】适用所有CC版的 openwrt 单线并发多拨教程!!!
  11. html th中加斜杠,css 模拟表格斜线
  12. 6、学习大数据笔记-hdfs读写代码
  13. SpringBoot实现通过邮箱找回密码功能
  14. 基于OpenCV的手指只数检测
  15. MICRO和GO-MICRO
  16. 小学生计算机清除键是mc,我的世界一键清除指令 | 手游网游页游攻略大全
  17. 不明真相的http code 497
  18. sql server link服务器
  19. pano2vr保存的html打不开,输出后的打开问题
  20. Jetson Nano 致命问题——TF卡损坏

热门文章

  1. 基于p5.js的物理学模拟小游戏
  2. python编的俄罗斯方块游戏_Python使用pygame模块编写俄罗斯方块游戏的代码实例
  3. python 箱线图
  4. Error compiling template
  5. golang 导出excel表格的两个包使用对比
  6. 企业信息与网络通信安全 团队成员简历-黎萍 (转)
  7. arduino UNO总是上传项目出错 问题的解决
  8. 直接启动、星三角启动、自耦降压启动、软启动,哪种方式适合消防水泵控制器?
  9. Highcharts饼状图调整字体大小,颜色等
  10. 计算机常见的智能终端有哪些,2019年中国智能终端行业市场规模,及主要细分领域出货量情况 [图]...