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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:10:57