You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 14中如何让ScrollView内自适应列LazyVGrid内容水平居中?

iOS14 中实现 LazyVGrid 内容少时水平居中的方案

你当前代码里,LazyVGrid 使用 .adaptive 列布局时,内容较少会左对齐,核心原因是网格被强制设为占满容器宽度,导致单行内的 item 无法居中。以下是两种适配 iOS14 的解决方式:

方案一:根据内容数量动态切换布局(简单直观)

先计算容器内一行能容纳的最大 item 数量,当总 item 数 ≤ 该数量时,用 HStack 包裹并居中显示;超过时则沿用原 LazyVGrid 布局,逻辑清晰易维护。

import SwiftUI

struct MyView: View {
    var numbers = 1...30
    private let itemSize: CGFloat = 50
    private let gridSpacing: CGFloat = 5
    
    var body: some View {
        VStack {
            GeometryReader { geometry in
                ScrollView {
                    // 计算容器可用宽度(减去默认左右padding的16*2)
                    let availableWidth = geometry.size.width - 32
                    // 计算一行最多能放的item数量
                    let maxItemsPerRow = Int((availableWidth + gridSpacing) / (itemSize + gridSpacing))
                    
                    if numbers.count <= maxItemsPerRow {
                        // 内容不足一行,用HStack居中展示
                        HStack(spacing: gridSpacing) {
                            ForEach(numbers, id: \.self) { i in
                                Text(String(i))
                                    .frame(width: itemSize, height: itemSize)
                                    .border(.blue)
                            }
                        }
                        .border(.red)
                        .padding()
                        .frame(minHeight: geometry.size.height)
                        .frame(maxWidth: .infinity, alignment: .center)
                    } else {
                        // 内容超过一行,使用自适应列的LazyVGrid
                        let columns = [
                            GridItem(.adaptive(minimum: itemSize), spacing: gridSpacing)
                        ]
                        
                        LazyVGrid(columns: columns, spacing: gridSpacing) {
                            ForEach(numbers, id: \.self) { i in
                                Text(String(i))
                                    .frame(width: itemSize, height: itemSize)
                                    .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())

方案二:使用 PreferenceKey 获取内容宽度(通用适配)

通过自定义 PreferenceKey 捕获 LazyVGrid 的实际内容宽度,动态调整网格的显示宽度:当内容宽度小于容器宽度时居中,否则占满容器,适合需要保持 LazyVGrid 布局结构的复杂场景。

import SwiftUI

// 自定义PreferenceKey,用于捕获网格内容的最大宽度
struct GridContentWidthKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = max(value, nextValue())
    }
}

struct MyView: View {
    var numbers = 1...30
    private let itemSize: CGFloat = 50
    private let gridSpacing: CGFloat = 5
    @State private var gridContentWidth: CGFloat = 0
    
    var body: some View {
        VStack {
            GeometryReader { geometry in
                ScrollView {
                    let columns = [
                        GridItem(.adaptive(minimum: itemSize), spacing: gridSpacing)
                    ]
                    
                    LazyVGrid(columns: columns, spacing: gridSpacing) {
                        ForEach(numbers, id: \.self) { i in
                            Text(String(i))
                                .frame(width: itemSize, height: itemSize)
                                .border(.blue)
                                // 捕获每个item的位置,计算网格内容的最大宽度
                                .background(
                                    GeometryReader { proxy in
                                        Color.clear
                                            .preference(key: GridContentWidthKey.self, value: proxy.frame(in: .local).maxX)
                                    }
                                )
                        }
                    }
                    .border(.red)
                    .padding()
                    // 更新捕获到的网格内容宽度
                    .onPreferenceChange(GridContentWidthKey.self) { newWidth in
                        gridContentWidth = newWidth
                    }
                    // 动态设置网格宽度:内容宽度小于容器可用宽度时用内容宽度,否则占满容器
                    .frame(width: min(gridContentWidth + gridSpacing, geometry.size.width - 32) + 32)
                    .frame(minHeight: geometry.size.height)
                    .frame(maxWidth: .infinity, alignment: .center)
                }
            }
        }.frame(width: 500, height: 200)
    }
}

import PlaygroundSupport
PlaygroundPage.current.setLiveView(MyView())

内容的提问来源于stack exchange,提问作者Lysann Tranvouez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:01:03