我有一个条目列表,其中包含多个UI列,除第一列外,所有列都可以 * 水平 * 设置为唯一大小(即,它们的长度/长度与其内容要求一样)。我知道,对于第一个大小一致的列,我可以设置一个框架修饰符宽度来实现这一点,但我希望有一种更好、更灵活的方式来获得所需的行为。原因是我不相信解决方案是最优化的,以考虑用户的的显示大小,也不是列的实际最大内容宽度。也就是说,当显示大小设置为最大值时,设置的宽度不够宽,或者,如果设置为最大值,则在较小/常规显示大小上,设置的宽度将不必要地宽。
这是我目前最好的尝试:
GeometryReader { geometry in
VStack {
HStack {
HStack {
Text("9am")
Image(systemName: "cloud.drizzle").font(Font.title2)
.offset(y: 4)
}.padding(.all)
.background(Color.blue.opacity(0.2))
.cornerRadius(16)
VStack {
HStack {
Text("Summary")
.padding(.trailing, 4)
.background(Color.white)
.layoutPriority(1)
VStack {
Spacer()
Divider()
Spacer()
}
VStack {
Text("12°")
Text("25%")
.foregroundColor(Color.black)
.background(Color.white)
}.offset(y: -6)
Spacer()
}.frame(width: geometry.size.width/1.5)
}
Spacer()
}
HStack {
HStack {
Text("10am")
.customFont(.subheadline)
Image(systemName: "cloud.drizzle").font(Font.title2)
.offset(y: 4)
.opacity(0)
}
.padding(.horizontal)
.padding(.vertical,4)
.background(Color.blue.opacity(0.2))
.cornerRadius(16)
VStack {
HStack {
ZStack {
Text("Mostly cloudy")
.customFont(.body)
.padding(.trailing, 4)
.background(Color.white)
.opacity(0)
VStack {
Spacer()
Divider()
Spacer()
}
}
VStack {
Text("13°")
Text("25%")
.foregroundColor(Color.black)
.background(Color.white)
}.offset(y: -6)
Spacer()
}.frame(width: geometry.size.width/1.75)
}
Spacer()
}
}
}
对我来说,这看起来像:
正如你所看到的,上午10点比上午9点稍微宽一些。为了让它们尽可能的接近,我还在其中加入了一个云图标,尽管不透明度为零。理想情况下,上午10点的大小应该和上午9点一样,而不需要透明的云图标。更一般地说,有意义的是识别该列中最宽的HStack,然后无论其宽度是多少都将应用于所有其他列。我上面的代码是静态的用于演示目的。2它将是一个视图,通过一个行集合迭代呈现。
3条答案
按热度按时间mlmc2os51#
您可以使用动态帧修改器,如帧(.maxWidth:.infinity)修饰符来扩展视图,使其填充整个帧,即使帧是动态的。下面是一个示例,可以帮助您开始:
nwlls2ji2#
在https://www.wooji-juice.com/blog/stupid-swiftui-tricks-equal-sizes.html的指导下,我完成了这一点。
这是我希望确保所有行的UI水平大小相等,宽度设置为最大值的UI:
包含上述内容的堆栈具有OnPreferenceChange修改器:
奇迹就发生在这里:
顶部的链接最好地描述了每个人的目的。
最大宽度首选项键
这将定义一个新键,将缺省值设置为零,并在添加新值时,采用最宽的
确定宽度
这个视图只是一个空的(Color.clear)背景,但是我们的新首选项设置为它的宽度。我们稍后会回到清晰背景部分,但首先:有几种方法可以设置偏好,这里我们使用anchorPreference,为什么?
嗯,anchorPreference有“没有可用的概览”,所以我实际上没有一个好的答案,除了它在实践中似乎更可靠。是的,货物崇拜代码。哇!我有一种预感,它需要一个块和所有,SwiftUI可以重新运行该块,以获得更新的值时,有影响布局的变化。
我的另一个希望是,这些东西将得到更好的记录,以便我们可以更好地理解这些不同类型的用途,新的SwiftUI开发人员可以加入进来,而不必花费所有的时间在堆栈溢出或阅读像这样的博客文章。
总之,锚是一个表示视图中的维度或位置的令牌,但它不会直接给予你值,你必须用GeometryProxy来兑现它,才能得到实际值,所以,这就是我们所做的--为了得到值,你用它作为代理的下标,所以proxy[anchor].size.width得到了我们想要的,当锚是.bounds(我们传递给anchorPreference调用的值)时,它有点扭曲,但它完成了任务。
maximumSubViewWidth是从父视图传入的绑定变量,用于确保每个子视图引用的maximumSubViewWidth始终是最新的最大值。
这个问题的一个问题是,在整个行上有一个不想要的微妙但仍然明显的动画,任何UI都被调整到最大宽度。我所做的工作是向父容器添加一个动画修改器,该修改器从nil开始,在显式触发后切换回.default。
在用户显式地与行交互之后,我将self. initialized设置为true(就我而言,他们点击一行来展开显示附加信息)-这确保了初始动画不会错误地发生,但动画在那之后会恢复正常。我最初的尝试是在.onAppear修饰符中切换initialized的状态,以便更改是自动的,但这没有起作用,因为我“假设在初始出现之后可以进行尺寸调整。
另一件需要注意的事情(这可能表明,虽然这个解决方案的工作,它不是最好的方法)是我看到这个消息在控制台重复的每一个项目,或只是那些需要调整大小(不清楚,但警告总数=项目数):
绑定首选项MaximumWidthPreferenceKey尝试每帧更新多次。
如果有人能想出一种方法来实现上述同时避免这个警告,那么太好了!
更新:我已了解上述内容。
这实际上是一个重要的变化,因为如果不解决这个问题,我会看到这个专栏在随后的屏幕访问中变得越来越宽。
该视图有一个新的widthDetermined @State变量,该变量被设置为false,并在. onAppeared中变为true。
如果widthDetermined为false,即没有设置,我就只确定视图的宽度,我使用https://fivestars.blog/swiftui/conditional-modifiers.html中建议的条件修饰符来完成这一操作:
并且在视图中:
wn9m85ua3#
我有类似的问题。我的文本在一行的标签之一是从2个字符到20个字符不等。它搞乱了水平对齐,正如你所看到的。我正在寻找使这一列的行作为固定宽度。我想出了一些非常简单的东西。它为我工作。