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

SwiftUI自定义拟态按钮样式触发CommandsBuilder控制流报错如何解决?

解决方案

报错原因

你遇到的编译报错是因为SwiftUI的ViewBuilder结果构建器不允许在View构建闭包中直接执行非View返回类型的控制流代码,你之前的尝试是把switch逻辑或者偏移量计算直接写在了Group的View构建闭包里,所以触发了限制。

可行实现方案

方案1:提前计算偏移量(兼容你现有的get方法)

只需要把所有偏移量的计算逻辑移到makeBody方法最开头,先计算好所有需要的偏移值存储为局部常量,再在View构建代码中直接引用即可,修改后的makeBody代码如下:

func makeBody(configuration: Configuration) -> some View {
    // 提前计算所有偏移量,不放在ViewBuilder闭包里就不会触发编译错误
    let innerShadowX = CGFloat(getXoffetInnerShadow())
    let innerShadowY = CGFloat(getYoffsetInnerShadow())
    let innerHighlightX = CGFloat(getXoffetInnerHighlight())
    let innerHighlightY = CGFloat(getYoffsetInnerHighlight())
    let shadowX = CGFloat(getXoffsetShadow())
    let shadowY = CGFloat(getYoffsetShadow())
    let highlightX = CGFloat(getXoffsetHighlight())
    let highlightY = CGFloat(getYoffsetHighlight())
    
    return configuration.label
        .padding(padding ?? 30)
        .contentShape(Circle())
        .background(
            Group{
                if configuration.isPressed {
                    Circle()
                        .fill(bgColor ?? Color.backgroundColor)
                        .overlay(
                            Circle()
                                .stroke(Color.black.opacity(0.7), lineWidth: 4)
                                .blur(radius: 4)
                                .offset(x: innerShadowX, y: innerShadowY)
                                .mask(Circle().fill(LinearGradient(colors: [Color.black, Color.clear], startPoint: startPoint, endPoint: endPoint)))
                        )
                        .overlay(
                            Circle()
                                .stroke(bgColorOffset ?? Color.backgroundColorOffset, lineWidth: 8)
                                .blur(radius: 4)
                                .offset(x: innerHighlightX, y: innerHighlightY)
                                .mask(Circle().fill(LinearGradient(colors: [Color.clear, Color.black], startPoint: startPoint, endPoint: endPoint)))
                        )
                } else {
                    Circle()
                        .fill(bgColor ?? Color.backgroundColor)
                        .shadow(color: Color.black.opacity(0.25), radius: 10, x: shadowX, y: shadowY)
                        .shadow(color: bgColorOffset ?? Color.backgroundColorOffset.opacity(0.7), radius: 10, x: highlightX, y: highlightY)
                }
            }
        )
}

方案2:动态映射偏移量(更简洁,支持任意自定义方向)

你不需要枚举所有UnitPoint的情况,直接利用UnitPoint自带的x、y属性(取值范围0~1,(0,0)为左上,(1,1)为右下)映射为偏移量即可,代码更简洁,还支持用户传入任意自定义的方向点,你可以直接删除所有getXXX偏移量计算方法,修改makeBody代码如下:

func makeBody(configuration: Configuration) -> some View {
    // 直接通过endPoint的x、y计算偏移,0.5是中心基准点
    let xBase = (endPoint.x - 0.5) * 2
    let yBase = (endPoint.y - 0.5) * 2
    
    let innerShadowX = xBase * 1
    let innerShadowY = yBase * 1
    let innerHighlightX = xBase * -1
    let innerHighlightY = yBase * -1
    let shadowX = xBase * 5
    let shadowY = yBase * 5
    let highlightX = xBase * -5
    let highlightY = yBase * -5
    
    return configuration.label
        .padding(padding ?? 30)
        .contentShape(Circle())
        .background(
            Group{
                if configuration.isPressed {
                    Circle()
                        .fill(bgColor ?? Color.backgroundColor)
                        .overlay(
                            Circle()
                                .stroke(Color.black.opacity(0.7), lineWidth: 4)
                                .blur(radius: 4)
                                .offset(x: innerShadowX, y: innerShadowY)
                                .mask(Circle().fill(LinearGradient(colors: [Color.black, Color.clear], startPoint: startPoint, endPoint: endPoint)))
                        )
                        .overlay(
                            Circle()
                                .stroke(bgColorOffset ?? Color.backgroundColorOffset, lineWidth: 8)
                                .blur(radius: 4)
                                .offset(x: innerHighlightX, y: innerHighlightY)
                                .mask(Circle().fill(LinearGradient(colors: [Color.clear, Color.black], startPoint: startPoint, endPoint: endPoint)))
                        )
                } else {
                    Circle()
                        .fill(bgColor ?? Color.backgroundColor)
                        .shadow(color: Color.black.opacity(0.25), radius: 10, x: shadowX, y: shadowY)
                        .shadow(color: bgColorOffset ?? Color.backgroundColorOffset.opacity(0.7), radius: 10, x: highlightX, y: highlightY)
                }
            }
        )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 00:12:03