英文:
SwiftUI equivalent of UIStackView.Distribution.fillEqually
问题
VStack(spacing: 12) {
ForEach(viewModel.model.accounts, id: \.title) { account in
AccountView(account: account)
.padding(16)
.frame(maxHeight: .infinity)
.overlay(RoundedRectangle(cornerSize: .init(width: 4, height: 4)).stroke(Color.outlineGrey, lineWidth: 1))
}
}
.fixedSize(horizontal: false, vertical: true)
英文:
I'm trying to make a simple VStack in SwiftUI where each view in the stack has the same height. The heights should be equal to the least amount of space required for the biggest view in the stack.
My minimum deployment target is iOS 13.
Here is an example of what I want:
And this is what I currently have:
In UIKit this is done easily by making the vertical UIStackView with .fillEqually distribution and then setting the contentCompressionResistancePriority to .required for the vertical component while keeping contentHuggingPriority to usually .defaultLow.
However in SwiftUI I'm not sure how to achieve this in a dynamic way. I don't want to set hardcoded frame heights.
I've tried setting .frame(maxHeight: .infinity)
alongside .fixedSize(horizontal: false, vertical: true)
but it doesn't seem to work in this scenario. I can do HStack with equal heights using this method and VStack with equal widths. But it doesn't seem to work for VStack with equal height and presumably also HStack equal width.
This is my code so far:
struct AccountSelectionView: View {
@ObservedObject private(set) var viewModel: AccountSelectionViewModel
var body: some View {
VStack(spacing: 12) {
ForEach(viewModel.model.accounts, id: \.title) { account in
AccountView(account: account)
.padding(16)
.frame(maxHeight: .infinity)
.overlay(RoundedRectangle(cornerSize: .init(width: 4, height: 4)).stroke(Color.outlineGrey, lineWidth: 1))
}
}
.fixedSize(horizontal: false, vertical: true)
Spacer()
}
}
struct AccountView: View {
let account: Account
var body: some View {
HStack {
Image(uiImage: account.image)
.padding(.trailing, 20)
VStack(alignment: .leading) {
Text(account.title)
.font(.appFont("Heavy", size: 16))
Text(account.message)
.font(.appFont("Roman", size: 14))
}
Spacer()
}
}
}
I've also tried adding .frame(maxHeight: .infinity)
and spacers to the AccountView but it didn't make a difference.
答案1
得分: 1
可以通过获取列表中视图的最大高度来实现这一点。
只需将你的AccountSelectionView
替换为以下代码。
struct AccountSelectionView: View {
@ObservedObject private(set) var viewModel: AccountSelectionViewModel
var body: some View {
VStack(spacing: 12) {
ForEach(viewModel.model.accounts, id: \.title) { account in
AccountView(account: account)
.padding(16)
.frame(minHeight: rowHeight)
.overlay(RoundedRectangle(cornerSize: .init(width: 4, height: 4)).stroke(Color.outlineGrey, lineWidth: 1))
.background(
GeometryReader{ (proxy) in
Color.clear.preference(key: HeightPreferenceKey.self, value: proxy.size)
})
.onPreferenceChange(HeightPreferenceKey.self) { (preferences) in
let currentSize: CGSize = preferences
if (currentSize.height > self.rowHeight) {
self.rowHeight = currentSize.height
}
}
}
}
Spacer()
}
}
这是用于保存最大高度的首选键。
struct HeightPreferenceKey: PreferenceKey {
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
nextValue()
}
typealias Value = CGSize
static var defaultValue: Value = .zero
}
英文:
You can achieve this by deriving the maximum height of your view inside the list.
for that just replace your AccountSelectionView with the below code.
struct AccountSelectionView: View {
@ObservedObject private(set) var viewModel: AccountSelectionViewModel
var body: some View {
VStack(spacing: 12) {
ForEach(viewModel.model.accounts, id: \.title) { account in
AccountView(account: account)
.padding(16)
.frame(minHeight: rowHeight)
.overlay(RoundedRectangle(cornerSize: .init(width: 4, height: 4)).stroke(Color.outlineGrey, lineWidth: 1))
.background(
GeometryReader{ (proxy) in
Color.clear.preference(key: HeightPreferenceKey.self, value: proxy.size)
})
.onPreferenceChange(HeightPreferenceKey.self) { (preferences) in
let currentSize: CGSize = preferences
if (currentSize.height > self.rowHeight) {
self.rowHeight = currentSize.height
}
}
}
}
Spacer()
}
}
and here is your preferred key for saving maximum height.
struct HeightPreferenceKey: PreferenceKey {
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
nextValue()
}
typealias Value = CGSize
static var defaultValue: Value = .zero
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论