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

SwiftUI中如何让视图与动态尺寸的另一View保持尺寸一致

解决方案

你可以通过 SwiftUI 的 PreferenceKey 捕获图片实际渲染后的高度,再将该高度同步给右侧文本容器即可实现需求,不需要使用会撑满父容器的外层 GeometryReader。

完整适配代码(兼容所有 SwiftUI 版本)

import SwiftUI

// 定义PreferenceKey用于存储图片的实际渲染高度
struct ImageHeightKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

struct TestScreen: View {
    // 存储动态获取到的图片高度
    @State private var imageHeight: CGFloat = 0
    
    var body: some View {
        VStack {
            HStack(spacing: 0) {
                // 左侧图片视图
                Image("blue-test-image")
                    .resizable()
                    .scaledToFit()
                    .frame(maxWidth: .infinity)
                    // 读取图片实际高度并存入PreferenceKey
                    .background(GeometryReader { geo in
                        Color.clear.preference(key: ImageHeightKey.self, value: geo.size.height)
                    })
                
                // 右侧文本容器
                VStack(spacing: 0) {
                    Text("Some Text")
                        .padding()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.gray)
                    Text("Other Text")
                        .padding()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.gray)
                }
                // 高度和动态获取的图片高度绑定
                .frame(maxWidth: .infinity, maxHeight: imageHeight)
            }
            // 监听图片高度变化更新状态
            .onPreferenceChange(ImageHeightKey.self) { height in
                imageHeight = height
            }
            
            Spacer()
        }
        .padding()
    }
}

简化版(仅 SwiftUI 4+ 可用)

如果你的项目适配最低版本为 iOS 16+/macOS 13+,可以用自带的 onSizeChange 修饰符省略自定义 PreferenceKey 的步骤:

import SwiftUI

struct TestScreen: View {
    @State private var imageHeight: CGFloat = 0
    
    var body: some View {
        VStack {
            HStack(spacing: 0) {
                Image("blue-test-image")
                    .resizable()
                    .scaledToFit()
                    .frame(maxWidth: .infinity)
                    // 直接读取图片尺寸
                    .onSizeChange { size in
                        imageHeight = size.height
                    }
                
                VStack(spacing: 0) {
                    Text("Some Text")
                        .padding()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.gray)
                    Text("Other Text")
                        .padding()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color.gray)
                }
                .frame(maxWidth: .infinity, maxHeight: imageHeight)
            }
            
            Spacer()
        }
        .padding()
    }
}

实现说明

  • 去掉外层 GeometryReader 避免其默认占满父容器全部可用高度的问题
  • 图片设置 scaledToFit 会根据自身宽高比和可用宽度自动计算高度,我们通过 PreferenceKey/onSizeChange 拿到这个动态高度
  • HStack 内两个子元素都设置 maxWidth: .infinity,会自动平分容器宽度,满足左右宽度相等的要求
  • 右侧文本容器高度绑定图片动态高度,两个文本块会自动平分该高度,总高度和图片完全一致
  • 无需写死任何固定尺寸,适配任意宽高比的图片

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 00:36:03