如何在SwiftUI中通过纯SwiftUI方式实现自定义GeometryReader
实现方案
你可以通过SwiftUI原生的PreferenceKey机制实现纯SwiftUI的尺寸读取,无需依赖UIKit桥接,完整实现如下:
首先定义内部用的尺寸存储PreferenceKey:
private struct SizePreferenceKey: PreferenceKey { static var defaultValue: CGSize = .zero static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() } }
然后修改你的CustomGeometryReaderView实现:
struct CustomGeometryReaderView<Content: View>: View { @ViewBuilder let content: (CGSize) -> Content // 存储读取到的可用尺寸 @State private var availableSize: CGSize = .zero var body: some View { // 撑满父视图提供的所有可用空间 Color.clear .background( // 背景层用GeometryReader读取当前视图的真实尺寸 GeometryReader { proxy in Color.clear .preference(key: SizePreferenceKey.self, value: proxy.size) } ) // 监听尺寸变化,更新State .onPreferenceChange(SizePreferenceKey.self) { newSize in availableSize = newSize } // 把真实尺寸传入content闭包渲染,对齐方式和系统GeometryReader保持一致 .overlay(content(availableSize), alignment: .topLeading) } }
使用方式和你原有代码完全兼容:
struct ContentView: View { var body: some View { CustomGeometryReaderView { proxy in Color.red .onAppear() { print(proxy) } } } }
说明
- 整个实现完全基于原生SwiftUI API,没有用到任何UIKit相关的桥接逻辑
- 布局行为和系统GeometryReader完全一致:自定义视图会先占满父视图提供的所有可用空间,再把读取到的尺寸传给内部内容,内容默认从左上角开始布局
- 如果需要扩展支持坐标空间查询、frame读取等能力,只需要把传给content的参数从CGSize替换为自定义的Proxy结构体,在PreferenceKey读取阶段采集对应参数即可
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

