SwiftUI实现Rectangle视图与Button1视图的尺寸及位置适配
SwiftUI 跨层级视图尺寸与位置适配方案
针对你需要让Rectangle与Button1对齐(用于教程高亮)的需求,这里可以通过PreferenceKey实现跨层级视图的尺寸与位置传递,具体方案如下:
1. 定义PreferenceKey传递视图Frame
首先创建一个自定义PreferenceKey,用来存储目标按钮的位置和尺寸信息:
struct ButtonFramePreferenceKey: PreferenceKey { static var defaultValue: CGRect = .zero static func reduce(value: inout CGRect, nextValue: () -> CGRect) { value = nextValue() } }
2. 修改按钮代码,传递自身Frame
给Button1添加background和preference修饰符,将按钮的全局坐标Frame传递出去:
Button {} label: { Text("1").foregroundColor(.white).padding().border(Color.white, width: 3).cornerRadius(5) } .background( GeometryReader { proxy in Color.clear .preference(key: ButtonFramePreferenceKey.self, value: proxy.frame(in: .global)) } )
3. 顶层读取Preference并控制Rectangle
在顶层ZStack中读取按钮的Frame,用@State变量存储,然后将这个Frame应用到Rectangle上:
完整修改后的代码:
struct TutorialView: View { @State private var button1Frame: CGRect = .zero var body: some View { ZStack { VStack { Spacer() HStack { Spacer() Button {} label: { Text("1").foregroundColor(.white).padding().border(Color.white, width: 3).cornerRadius(5) } .background( GeometryReader { proxy in Color.clear .preference(key: ButtonFramePreferenceKey.self, value: proxy.frame(in: .global)) } ) Spacer() Button {} label: { Text("2").foregroundColor(.white).padding().border(Color.white, width: 3).cornerRadius(5) } Spacer() Button {} label: { Text("3").foregroundColor(.white).padding().border(Color.white, width: 3).cornerRadius(5) } Spacer() Button {} label: { Text("4").foregroundColor(.white).padding().border(Color.white, width: 3).cornerRadius(5) } Spacer() } Spacer() } ZStack { Color.black.opacity(0.5) .ignoresSafeArea() // 适配按钮的Rectangle Rectangle() .cornerRadius(10) .frame(width: button1Frame.width, height: button1Frame.height) .position(x: button1Frame.midX, y: button1Frame.midY) .blendMode(.destinationOut) } .compositingGroup() } .background(Color.blue) .onPreferenceChange(ButtonFramePreferenceKey.self) { newFrame in button1Frame = newFrame } } } // 自定义PreferenceKey struct ButtonFramePreferenceKey: PreferenceKey { static var defaultValue: CGRect = .zero static func reduce(value: inout CGRect, nextValue: () -> CGRect) { value = nextValue() } }
关键说明
- GeometryReader:用来获取Button1的全局坐标Frame(
.global坐标系确保和顶层ZStack的坐标一致)。 - PreferenceKey:实现跨层级视图的数据传递,把按钮的Frame从子视图传递到顶层ZStack。
- position修饰符:通过按钮Frame的中点坐标,让Rectangle精准对齐按钮位置;同时用按钮的宽高设置Rectangle尺寸。
- 如果需要高亮效果更明显,可以给Rectangle的尺寸加一点额外的padding,比如
width: button1Frame.width + 10, height: button1Frame.height + 10。
内容的提问来源于stack exchange,提问作者buleva
相关产品推荐
相关产品推荐

