在 SwiftUI 中根据宽度计算每行的项目数

2024-01-30

这是我之前问题的延伸(在 SwiftUI 中使用获取视图的宽度 https://stackoverflow.com/questions/57577462/get-width-of-a-view-using-in-swiftui/57591483#57591483)

我需要实现一个布局,其中每行的项目数是根据其组合宽度动态确定的(基本上,将项目放在一行中,直到它们不再适合)。

有人告诉我,使用 GeometryReader 是用声明性语言做某事的一种老套方法,这显然是正确的。

我也被引导到这个类似于 CollectionView 的组件https://github.com/Q-Mobile/QGrid https://github.com/Q-Mobile/QGrid但解决方案是静态的,因为在渲染任何组件之前,行数和每行单元格数确定一次。

我不知道如何解决这个问题,所以任何建议对我来说都非常有价值!

❤️❤️❤️


TL;DR

GeometryReader 可能是一个“hacky”解决方案,但它是我们目前拥有的解决方案。它is可以创建一个动态回流少量项目或延迟回流大量项目的解决方案。我的演示代码 https://github.com/john-mueller/SwiftUI-Examples/tree/master/SwiftUI-Examples/FlowLayout在这里会很笨拙,但听起来描述我的方法可能会有用。

运用我们现有的资源

在幕后,SwiftUI 正在执行各种优化的约束求解,以有效地布局视图。理论上,像您所描述的那样重排内容可能是约束解决的一部分;在今天的 SwiftUI 中,情况并非如此。因此,执行您所描述的操作的唯一方法是以下某些变体:

  1. 让 SwiftUI 根据我们的数据模型来布置一切。
  2. 获取 SwiftUI 使用几何读取器和首选项/回调决定的宽度。
  3. 使用这些宽度来解决我们的回流约束。
  4. 更新数据模型,这将触发步骤1。

希望这个过程能够收敛到稳定的布局,而不是进入无限循环。

我的结果

玩过之后,这就是我到目前为止所得到的。您可以看到,当宽度发生变化时,少量项目(在我的示例中为 29 个)几乎立即回流。对于大量项目(在我的示例中为 262 个),会出现明显的延迟。如果内容和视图宽度不发生变化并且不需要经常更新,这应该不是什么大问题。时间几乎全部花在步骤 1 上,因此,在我们在 SwiftUI 中获得适当的回流支持之前,我怀疑这已经是最好的了。 (如果您想知道,一旦回流完成,垂直滚动视图就会以正常的响应速度滚动。)

我的策略

本质上,我的数据模型始于[String]数组并将其转换为[[String]]数组,其中每个内部数组对应于在我的视图中水平放置的一行。 (从技术上讲,它始于String在空白处分割以形成[String],但从广义上讲,我有一个想要分成多行的集合。)然后我可以使用它来布局它VStack, HStack, and ForEach.

我的第一个方法是尝试读取我正在显示的实际视图的宽度。然而,我很快遇到了无限递归或奇怪的不稳定振荡​​,因为它可能会截断文本视图(例如[四] [分数] [和] [se...]),然后一旦回流改变,就取消截断一次,返回来回(或者只是以截断状态结束。

所以我决定作弊。我将所有单词放在第二个不可见的水平滚动视图中。这样,它们就可以占用尽可能多的空间,并且永远不会被截断,最重要的是,因为这种布局仅取决于[String]数组而不是派生的[[String]]数组,它永远不能进入递归循环。您可能认为将每个视图放置两次(一次用于测量宽度,一次用于显示)效率低下,但我发现它比尝试从显示的视图测量宽度要快数十倍,并且 100% 产生正确的结果时间。

+---------- FIRST TRY - CYCLIC ----------+  +-------- SECOND TRY - ACYCLIC --------+
|                                        |  |                                      |
|    +--------+ [String] +----------+    |  |   +-------+ [String] +--------+      |
|    |                              |    |  |   |                           |      |
|    | +--------------------------+ |    |  |   v                           v      |
|    | |                          | |    |  | Hidden +-->  Widths  +--> [[String]] |
|    v v                          + v    |  | layout                        |      |
|  Display +-->  Widths  +--> [[String]] |  |                               v      |
|  layout                                |  |                            Display   |
|                                        |  |                            layout    |
+----------------------------------------+  +--------------------------------------+

为了读取和保存宽度,我采用了 GeometryReader/PreferenceKey 方法详细信息请参见 swiftui-lab.com https://swiftui-lab.com/communicating-with-the-view-tree-part-1/。宽度保存在视图模型中,并在隐藏滚动视图中的视图数量或大小发生变化时更新。这样的更改(或更改视图的宽度)然后会回流[String]数组到[[String]]基于模型中保存的宽度。

Summary

现在,这些在运输应用程序中是否有用将取决于您想要回流的项目数量,以及它们在布局后是否是静态的或经常更改。但我发现这是一个令人着迷的消遣!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 SwiftUI 中根据宽度计算每行的项目数 的相关文章

  • Swift MKAnnotationView 旋转

    我试图在坐标更改时旋转我的自定义注释 我可以成功地更改坐标 但尝试了一切方法来旋转它 但没有成功 基本思想是有一个平面并通过旋转设置其方向 这是我的代码 import UIKit import MapKit class CustomPoin
  • 如何使自定义键盘扩展再次成为第一响应者

    我正在制作一个自定义键盘扩展 在这个键盘中 我有另一个 uitextfield 作为搜索字段 因此当我在自定义键盘上键入时 我不会将文本发送到 safari 的文本字段或某些聊天应用程序的文本字段 而是发送将文本发送到自定义键盘中的 uit
  • React.js:参考在初始渲染时不可用

    我试图在组件的根 DOM 元素的中间放置一个圆圈 var App React createClass render function return
  • 更新 iOS 应用程序的应用内购买内容?

    我似乎无法在任何地方找到这个问题的答案 所以这里 我正在开发一个 iOS 应用程序 该应用程序将具有非消耗性应用内购买 扩展包 例如 假设我出售一个包含 10 个级别的包 并且在一个月内我想将应用内购买更新为包含 15 个级别 用户无需重新
  • 在 iMessage 应用程序中检查横向/纵向方向(扩展)

    见过很多检查方向的解决方案 但奇怪的是 没有一个有效 下面是代码片段 override func viewWillTransition to size CGSize with coordinator UIViewControllerTran
  • App Store Connect 上传错误“您尚未获得云管理分发证书的访问权限”

    使用 Xcode 将 iOS 应用程序上传到 App Store Connect 自动管理签名 并收到此错误 查找和生成签名资产时发生以下错误 与苹果通讯失败 您尚未获得云管理分发证书的访问权限 请联系您团队的帐户持有人或管理员以授予您访问
  • Three20 和 iOS 6 不工作

    我刚刚尝试了我的一个项目 其中包含 Three20 但它似乎无法编译 给我构建错误 似乎是因为一些 UITouch 界面发生了变化 想知道是否有快速修复方法可以做到这一点 看来问题是在这里 UITouch ivars 已从 iOS 6 SD
  • 如果我在新证书上续订我的配置文件(企业分发方法),我的应用程序是否会停止?

    我有一个通过企业分发方法发布的应用程序 分发证书将在一个月后过期 因此我创建了一个新证书 此外 我还根据具有相同捆绑 ID 和应用 ID 的新证书更新了配置文件 旧的配置文件将像旧证书一样在 1 个月后过期 我的应用程序是通过此配置文件和证
  • 如何在 Objective-C 中的导航栏中央添加图像?

    我正在IOS中开发 我使用以下代码来设置背景navigationBar self navigationController navigationBar setBackgroundImage UIImage imageNamed bar ba
  • 翻转通过CVOpenGLESTexture获得的OpenGL ES纹理

    在我尝试 OpenGL ES 2 0 的最后一天 当我尝试将两个投影纹理 一个精灵动画和一个视频文件纹理 应用到天空盒时 我开始像存根一样简单地用手敲击键盘 奇迹般地它就成功了 一切都开始工作了 然而 从视频文件创建的纹理是颠倒的 换句话说
  • 修改多张照片时只有一个 iOS 权限对话框

    我的应用程序允许用户从相机胶卷中选择多个图像并对这些图像应用编辑 但是 它会提示用户获得每个图像编辑的权限 编辑用户图像时是否可以只显示一个权限对话框 如果是 我该如何将我的编辑分组为一项权限 这是我的应用程序的屏幕截图 我在应用商店中发现
  • iOS 上的内存交换和虚拟内存 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 Does iOS支持像Linux一样自动运行的内存交换和虚拟内存吗 iOS有虚拟内存 但没有后备存储 因此没有交换内存的调入 调出 A
  • 如何显示启动图像

    我是 iOS 新手 我的 Xcode 版本是 7 2 1 我尝试使用 Swift 在 iOS9 上运行 我的问题是我对如何创建启动屏幕图像感到非常困惑 我发现有很多方法可以为不同版本的 iOS 创建启动屏幕图像 有人可以向我解释一下如何设置
  • 管理 iOS 中的布局

    我是新来的iOS开发方面 我对 JAVA Swing 和 Windows 应用程序有扎实的背景 我想学习如何进行布局iOS 我猜iOS没有 布局管理器 就像 Java Swing 中的那样 发展的唯一出路UI是否指定每个控制器的尺寸和位置
  • 为什么数组不符合 Equatable,而它的项在 Swift 中是 Equatable?

    UPDATE 从 Xcode 9 3 开始 包括斯威夫特 4 1 数组相等按预期工作 并且原始问题中的代码编译没有错误 然而 请查看已接受的答案 因为它提供了更好 更现代的解决方案 原问题如下 当我尝试声明类型为泛型枚举的实例时 Post
  • 错误 ITMS-90596:“捆绑包无效。无法处理“Payload/ExpoKitApp.app/.bundle/Assets.car”处的资产目录。”

    问题摘要 我想向Apple App store TestFlight 提交一个应用程序 我正在使用 Transporter v1 1 提交应用程序 在提交过程中 我在 Transporter 中收到以下错误 请注意 我在此过程中没有使用 X
  • FlurrySDK 与 cocoapods

    我正在尝试使用 Cocoapods 将 FlurrySDK 框架集成到我的应用程序中 正如我已经使用很多框架所做的那样 但由于某种原因 xcode 不断抛出此编译错误 Undefined symbols for architecture a
  • SwiftUI:如何更新由一组静态数据驱动的列表并从另一组动态数据中提取一些信息?

    我什至不确定标题问题是否有意义 不管怎样 请继续阅读 编辑 交叉链接到苹果开发者论坛 https developer apple com forums thread 663208 编辑 这是源代码 http git morpheu5 net
  • 使用 Xcode 6 XLIFF 导出的 iOS 本地化/国际化设置 Bungle

    背景 Xcode 6 添加了快速导出功能 可为每种语言创建单个 XLIFF 文件 只需从文件导航器中选择您的项目 然后选择菜单项编辑器 导出以进行本地化 Issue 它工作得非常好 并且 XML 中包含了所有内容 除了设置捆绑字符串 有人有
  • iPad 的自适应布局

    我正在关注这篇文章在 ios 中构建自适应布局为 iOS 8 构建自适应用户界面 http www sitepoint com building adaptive user interfaces ios 8 它在 iPhone 上运行良好

随机推荐

  • 使用 Ramda 在循环中从多个数组中取出前 X 个总项目

    我有一个数组数组 想编写一个返回顶部的函数x项目数 通过按顺序从每个数组中获取项目 这是我所追求的一个例子 const input 1a 2a 3a 4a 5a 1b 2b 3b 4b 5b 1c 2c 3c 4c 5c 1d 2d 3d
  • 常见的日志记录 jar 与 Apache 轴 Soap 客户端冲突

    我在尝试使用 axis 调用 SOAP Web 服务时遇到此异常 基本上我已经写了一个轴客户端 org apache commons discovery DiscoveryException Class org apache commons
  • 了解 Zeromq Java 绑定

    我正在研究 Zeromq 作为 Java 项目中的消息传递解决方案 但我发现有关 Java 绑定的说明有点难以遵循 http www zeromq org bindings java http www zeromq org bindings
  • C# 获取非托管 dll 的版本

    我正在从托管 c 代码调用非托管 dll 并想检查我正在调用正确的版本 我尝试加载程序集 然后获取资源文件 然后获取版本 的代码是 cur version Assembly LoadFile X Workspace yreceipts po
  • 等待用户从终端输入 R

    当从命令行运行我的脚本作为 Rscipt myscript R 时 我能够等待 R 中的用户输入 如下所示并从 stdin 读取输入 cat Enter word word lt readLines file stdin 1 print w
  • 使用 .cssRules 访问跨域样式表

    当我尝试访问外部域上托管的某些 CSS 文件时 我在 Firebug 中收到此错误 Security error code 1000 rules styleSheets i cssRules 我正在使用的代码是 document ready
  • 使用 youtube-dl 搜索 Youtube 视频

    我正在尝试构建一个 Discord 音乐机器人 我需要使用用户给出的关键字搜索 YouTube 目前我知道如何从网址播放 loop loop or asyncio get event loop data await loop run in
  • 将 C++/CLI 与 NUnit 结合使用的限制

    这个答案 https stackoverflow com questions 13699 choosing a c unit testing toolframework 13897关于 C 单元测试框架的问题提出了一种我以前没有想到的可能性
  • 在不使用索引的情况下替换 pandas DataFrame 中选定单元格的值

    这是一个非常相似的问题这个问题 https stackoverflow com questions 13842088 set value for particular cell in pandas dataframe但有一个关键的区别 我选
  • GitHub:如何将开放的拉取请求添加到本地存储库?

    我正在使用NSDate 扩展 https github com erica NSDate Extensions我的 iOS Xcode 项目中的插件 主存储库有一些错误 似乎在两个 Pull 请求中得到了修复 https github co
  • django TypeError:get() 获得关键字参数“invoice_id”的多个值

    我对 python 和 django 比较陌生 我有以下其余 api 视图 class InvoiceDownloadApiView RetrieveAPIView This API view will retrieve and send
  • 缺少rabbitMQ配置文件

    我正在使用 Rabbitmq 3 7 2 和 Erlang 20 2 并且 bydefualt RMQ 配置文件丢失 在以下路径 C Users vxadmin AppData Roaming RabbitMQ config 基于我采取的步
  • 在 Android 上添加的文件夹通过 USB 不可见

    我正在尝试将图片保存在 Android 上的子文件夹中 这是我的一些代码 File path Environment getExternalStoragePublicDirectory Environment DIRECTORY DCIM
  • R - 按列名 AS CHARACTER 对 data.frame 进行排序

    我知道我可以这样订购 data frame test data frame A c 4 2 4 B c 8 3 2 ordered test with test order A B 但是 当列由列名指定为字符变量时 如何完成同样的事情呢 这
  • Lua - 初始化[重复]

    这个问题在这里已经有答案了 我无法在 Arch Linux 下正确初始化 lua Lua 最新版本 这是我的代码 include
  • 为特定风格和 buildType 定义 buildconfigfield

    我有两种口味 比如说香草和巧克力 我还有 调试 和 发布 构建类型 并且我需要 Vanilla Release 的字段为 true 而其他 3 个组合应该为 false def BOOLEAN boolean def VARIABLE VA
  • 检测 window.location 的变化

    我正在尝试检测 window location 中的更改 例如 如果用户尝试重新加载页面 则会收到通知 但我似乎找不到方法来做到这一点 有一些与之相关的事件吗 Thanks The unload当用户离开页面时触发该事件 还有一个befor
  • 异步/同步 JavaScript

    我在理解异步和同步 Javascript 之间的区别时遇到了一些困难 希望有人能对此有所了解 我知道 Javascript 本质上是同步的 但您可以使用异步事件 回调来改变程序流程 但是 如果您调用包含 AJAX 且没有回调的函数 会发生什
  • 通过 url 将参数传递给 python azure 函数

    我试图通过 azure 函数使 hello world 示例适用于 python 基本函数尝试通过 url 检索输入的名称 然后响应 Hello Name 事实证明 通过天蓝色门户提供的示例模板不能开箱即用 基本示例如下所示 import
  • 在 SwiftUI 中根据宽度计算每行的项目数

    这是我之前问题的延伸 在 SwiftUI 中使用获取视图的宽度 https stackoverflow com questions 57577462 get width of a view using in swiftui 57591483