第九章 List|GeometryReader|ForEach

但是我们的服务器地址需要满足用户在我们的支持的环境切换,所以需要一个类似 PopMenuButton的控件,在Mac上我们可以使用 Picker控件,甚至还有 ContextMenu 控件,但是好像都不满足。

那么我们就自己做一个下面这样的控件。

其实 FlutterPopMenuButton的体验要复杂的多,我们只做简单的版本,可以满足用户可以选择切换服务器。

这个组件不止在登陆页面用,以后还用到切换工厂等操作,我们将这个组件放在 Common 同级目录创建一个文件夹 View,新建 PopMenuButton.swift

我们可以看到弹出是可以选择的,数据源是外部的,意思是数据源是不确定的,那么就需要做成滚动,但是也有最大高度限制。

使用 List 将内容可以滚动

既然是滚动的,我们就用到了 List 这个组件。比如下面代码

swift 复制代码
struct PopMenuButton: View {
    var body: some View {
        List {
            Text("Hello, World!")
            Text("Hello, World!")
            Text("Hello, World!")
        }
    }
}

我们发现List是充满整个页面的。并且在样式上面系统默认做了很多默认边距,可是我们不想要默认产生的间距。

我对于 List 的了解也不是很多,所以也不是很清楚怎么弄,我就用谷歌搜索了关键词。swiftui list remove edge

通过查看相关的资料,我获取了两个关键词一个是设置 listStyle,一个设置 listRowInsets

swift 复制代码
var body: some View {
    List {
        Text("Hello, World!")
            .listRowInsets(EdgeInsets())
        Text("Hello, World!")
            .listRowInsets(EdgeInsets())
        Text("Hello, World!")
            .listRowInsets(EdgeInsets())
    }
    .listStyle(PlainListStyle())
}

使用 GeometryReader 查看视图大小

从运行结果看,对于每一个Row还是存在一个默认最小的高度44。为了验证我们的猜测,我们用到了一个可以自由布局的组件 GeometryReader

GeometryReader 可以获取容器的大小,从而开始自由的布局,我们将代码修改一下,显示一下布局大小。

swift 复制代码
GeometryReader { geo in
    return Text("size: \(geo.size.debugDescription)")
}
.listRowInsets(EdgeInsets())

界面上显示当前 Cell 的大小为 390x44,果然最小的高度为44

我们也不想这个 List 充满整个屏幕呀,我们设置 fixedSize。我们发现报错了,List这个组件不支持自身按照内容调节高度。

我们设置一个最大高度试一下,比如最多显示五行半,假设一行就按照44高度计算,那么最大的高度为。

swift 复制代码
44 * 5.5 = 242

我们给 List 设置一下最大的高度。

List 的大小确实变小了,但是我们只有三行,那么高度岂不是多出来了。这样体验不是很好,因为 List 默认高度是最大的高度,现在设置了最多 242 高度,所以现在计算出 List 的高度为 242 的高度。

通过 .frame(height:) 设置具体高度

如果我们只显示三行的高度,那么就需要去设置 ListFrame 的高度。

swift 复制代码
/// 44 * 3 = 132
.frame(height: 132)

List 的高度已经变成我们内容的真正的高度,我们将高度设置 500 试一下,看看最大的高度是否还是 242

从结果来看,我们设置最大高度 242 已经失效。为了能够达到我们的体验,如果大于 5 行,那么最大的高度就是 5.5 行,如果小于等于 5 行,就显示真正的高度。

swift 复制代码
final var listHeight:CGFloat {
	let number = min(5.5,rowNuber)
	return number * 44
}

想要知道 List 的行数,那么就要知道数据源,我们新建一个属性,接受外部传递进来的服务器地址列表。

swift 复制代码
let items:[String]

使用 ForEach 动态添加子视图

刚才我们是一个个加进 List,但是如果有一组数据,怎么能够循环的添加呢?这个时候我们需要用到 ForEach 的组件。

swift 复制代码
List {
    ForEach(items, id: \.self) { item in
        Text(item)
            .listRowInsets(EdgeInsets())
    }
}

我们去掉刚才设置的 maxWidth ,将 height 设置为我们计算出来的高度的值。我们将数据源设置为6条,看一下效果。

和我们预想的一样,虽然这样实现了我们的效果,但是我们目前是每一条数据都是固定高度计算出来的,如果每一条的高度不一致,那么对于我们计算高度就会很麻烦。

相关推荐
东坡肘子4 天前
春晚、机器人、AI 与 LLM -- 肘子的 Swift 周报 #124
人工智能·swiftui·swift
君赏5 天前
第三十二章 接下来我们开始做`灭菌整板`页面
swiftui
君赏5 天前
第三十章 接下来我们写首页的功能,首先是我们的`托盘绑定箱号`。
swiftui
君赏5 天前
第三十一章 完善箱号列表
swiftui
君赏5 天前
第二十五章 完善登录逻辑
swiftui
君赏5 天前
第二十六章 Focused
swiftui
君赏5 天前
第 二十章 @Published sink
swiftui
君赏5 天前
第二十一章 @ViewBuilder默认实现|Toggle|我的页面封装
swiftui
君赏5 天前
第二十九章 修复首页 PopMenuView 显示问题
swiftui
君赏5 天前
第二十八章 重置 ObservableObject 模型数据
swiftui