admin管理员组文章数量:1122846
I have a LazyVGrid inside a ScrollView with a single adaptive column.
import SwiftUI
struct MyView: View {
var numbers = 1...30
var body: some View {
let columns = [
GridItem(.adaptive(minimum: 50), spacing: 5)
]
VStack {
GeometryReader { geometry in
ScrollView {
LazyVGrid(columns: columns, spacing: 5) {
ForEach(numbers, id: \.self) { i in
Text(String(i))
.frame(width: 50, height: 50)
.border(.blue)
}
}
.border(.red)
.padding()
.frame(minWidth: geometry.size.width, minHeight: geometry.size.height)
}
}
}.frame(width: 500, height: 200)
}
}
import PlaygroundSupport
PlaygroundPage.current.setLiveView(MyView())
This looks fine when there are a lot of items in the grid:
But when there are few items, I would prefer the items to be centered. Instead, they are left-aligned in a single row. The LazyVGrid appears to take up all the horizontal space, even if it doesn't need it.
How can I achieve horizontal centering, on iOS 14?
NB: The ScrollView may not have anything to do with the problem at hand. But I mention it because I had to use GeometryReader in order to vertically center the contents when using a ScrollView.
I have a LazyVGrid inside a ScrollView with a single adaptive column.
import SwiftUI
struct MyView: View {
var numbers = 1...30
var body: some View {
let columns = [
GridItem(.adaptive(minimum: 50), spacing: 5)
]
VStack {
GeometryReader { geometry in
ScrollView {
LazyVGrid(columns: columns, spacing: 5) {
ForEach(numbers, id: \.self) { i in
Text(String(i))
.frame(width: 50, height: 50)
.border(.blue)
}
}
.border(.red)
.padding()
.frame(minWidth: geometry.size.width, minHeight: geometry.size.height)
}
}
}.frame(width: 500, height: 200)
}
}
import PlaygroundSupport
PlaygroundPage.current.setLiveView(MyView())
This looks fine when there are a lot of items in the grid:
But when there are few items, I would prefer the items to be centered. Instead, they are left-aligned in a single row. The LazyVGrid appears to take up all the horizontal space, even if it doesn't need it.
How can I achieve horizontal centering, on iOS 14?
NB: The ScrollView may not have anything to do with the problem at hand. But I mention it because I had to use GeometryReader in order to vertically center the contents when using a ScrollView.
Share Improve this question edited Nov 21, 2024 at 19:55 Lysann Tranvouez asked Nov 21, 2024 at 17:08 Lysann TranvouezLysann Tranvouez 93610 silver badges16 bronze badges 1- Ths post might help: Center alignment in row of LazyVGrid – Benzy Neez Commented Nov 21, 2024 at 17:16
1 Answer
Reset to default 0I ended up making a custom AdaptiveVGrid
implementation, loosely based on this tutorial: https://www.fivestars.blog/articles/adaptive-swiftui-views/
I'm very new to SwiftUI, so there's likely some issues with the implementation. Take it with a grain of salt. It's quite verbose at least.
I'll leave this question open in case anyone has a better approach.
/// A view to display items in a grid, while adapting to the available space, item size, and number of items.
/// When items can fit in one row or column, prefer that (depending on whether we have more horizontal or vertical space).
/// Otherwise uses a LazyVGrid insize a ScrollView to display the content.
///
/// content should have the number of subviews specified as numItems.
struct AdaptiveVGrid<Content: View>: View {
var numItems: Int
var itemMinSize: CGSize
var itemMaxSize: CGSize
var itemSpacing: CGFloat
var content: Content
public init(
numItems: Int,
itemMinSize: CGSize,
itemMaxSize: CGSize,
itemSpacing: CGFloat,
@ViewBuilder content: () -> Content
) {
self.numItems = numItems
self.itemMinSize = itemMinSize
self.itemMaxSize = itemMaxSize
self.itemSpacing = itemSpacing
self.content = content()
}
var body: some View {
GeometryReader { geometry in
bodyImpl(availableSize: geometry.size)
.frame(minWidth: geometry.size.width, minHeight: geometry.size.height)
}
}
@ViewBuilder
func bodyImpl(availableSize: CGSize) -> some View {
let widthRatio = availableSize.width / (CGFloat(numItems) * itemMaxSize.width + CGFloat(numItems - 1) * itemSpacing)
let heightRatio = availableSize.height / (CGFloat(numItems) * itemMaxSize.height + CGFloat(numItems - 1) * itemSpacing)
if widthRatio >= heightRatio && availableSize.width >= (CGFloat(numItems) * itemMinSize.width + CGFloat(numItems - 1) * itemSpacing) {
HStack(spacing: itemSpacing) { content }
} else if heightRatio >= widthRatio && availableSize.height >= (CGFloat(numItems) * itemMinSize.height + CGFloat(numItems - 1) * itemSpacing) {
VStack(spacing: itemSpacing) { content }
} else {
ScrollView {
let columns = [GridItem(.adaptive(minimum: itemMinSize.width, maximum: itemMaxSize.width), spacing: itemSpacing)]
LazyVGrid(columns: columns, alignment: .center) {
content
}
.frame(minWidth: availableSize.width, minHeight: availableSize.height)
}
}
}
}
struct MyView: View {
@ObservedObject var viewModel: MyModel
@ScaledMetric var accessabilityScale: CGFloat = 1
@State private var availableSize: CGSize = .zero
private let itemMinSizeBase = CGSize(width: 100, height: 100)
private let itemMaxSizeBase = CGSize(width: 250, height: 250)
private let itemSpacingBase = 20.0
var body: some View {
GeometryReader { geometry in
AdaptiveVGrid(
numItems: viewModel.items.count,
itemMinSize: adjustSize(itemMinSizeBase, availableSize: geometry.size),
itemMaxSize: adjustSize(itemMaxSizeBase, availableSize: geometry.size),
itemSpacing: itemSpacingBase * accessabilityScale
) {
ForEach(viewModel.items, id: \.id) { item in
itemView(item: item)
.frame(minWidth: adjustSize(itemMinSizeBase, availableSize: geometry.size).width,
maxWidth: CGFloat.greatestFiniteMagnitude,
minHeight: adjustSize(itemMinSizeBase, availableSize: geometry.size).height,
maxHeight: adjustSize(itemMaxSizeBase, availableSize: geometry.size).height
)
}
.padding()
}
}
}
private func adjustSize(_ size: CGSize, availableSize: CGSize) -> CGSize {
CGSize(width: min(size.width, availableSize.width),
height: min(size.height * accessabilityScale, availableSize.height))
}
}
本文标签: swiftHorizontally center contents of LazyVGrid inside ScrollView with adaptive columnsStack Overflow
版权声明:本文标题:swift - Horizontally center contents of LazyVGrid inside ScrollView with adaptive columns - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736308636a1933734.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论