1

我制作了一种按钮样式来在我的应用程序中创建圆形神经拟态按钮,如下所示:

struct NeumorphicCircleButtonStyle: ButtonStyle {
    var startPoint: UnitPoint
    var endPoint: UnitPoint
    var padding: CGFloat?
    var bgColor: Color?
    var bgColorOffset: Color?
    
    func makeBody(configuration: Configuration) -> some View {
        
        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: 2, y: 2)
                                    .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: -2, y: -2)
                                    .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: 10, y: 10)
                            .shadow(color: bgColorOffset ?? Color.backgroundColorOffset.opacity(0.7), radius: 10, x: -5, y: -5)
                    }
                }
            )
    }
    
    // TODO: this will change the x y on the first set and need to make for other x y sets for direction, but can't find a good place for the logic, can't call it from in the makebody anywhere
    func getXoffetInnerShadow() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return 2
        case .bottomLeading:
            return -2
        case .topTrailing:
            return 2
        case .topLeading:
            return -2
        case .leading:
            return -2
        case .trailing:
            return 2
        default:
            return 0
        }
    }
    
    func getYoffsetInnerShadow() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return 2
        case .bottomLeading:
            return 2
        case .bottom:
            return 2
        case .topTrailing:
            return -2
        case .topLeading:
            return -2
        case .top:
            return -2
        default:
            return 0
        }
    }
    
    func getXoffetInnerHighlight() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return -2
        case .bottomLeading:
            return 2
        case .topTrailing:
            return -2
        case .topLeading:
            return -2
        case .leading:
            return 2
        case .trailing:
            return -2
        default:
            return 0
        }
    }
    
    func getYoffsetInnerHighlight() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return -2
        case .bottomLeading:
            return -2
        case .bottom:
            return -2
        case .topTrailing:
            return 2
        case .topLeading:
            return 2
        case .top:
            return 2
        default:
            return 0
        }
    }
    
    func getXoffsetShadow() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return 10
        case .bottomLeading:
            return -10
        case .topTrailing:
            return 10
        case .topLeading:
            return -10
        case .leading:
            return -10
        case .trailing:
            return 10
        default:
            return 0
        }
    }
    
    func getYoffsetShadow() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return 10
        case .bottomLeading:
            return 10
        case .bottom:
            return 10
        case .topTrailing:
            return -10
        case .topLeading:
            return -10
        case .top:
            return -10
        default:
            return 0
        }
    }
    
    func getXoffsetHighlight() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return -10
        case .bottomLeading:
            return 10
        case .topTrailing:
            return -10
        case .topLeading:
            return 10
        case .leading:
            return 10
        case .trailing:
            return -10
        default:
            return 0
        }
    }
    
    func getYoffsetHighlight() -> Int {
        switch endPoint {
        case .bottomTrailing:
            return -10
        case .bottomLeading:
            return -10
        case .bottom:
            return -10
        case .topTrailing:
            return 10
        case .topLeading:
            return 10
        case .top:
            return 10
        default:
            return 0
        }
    }
}


    // this is how I init my gradient if you want a working example
extension LinearGradient {
    init(_ colors: Color..., startPoint: UnitPoint, endPoint: UnitPoint) {
        self.init(gradient: Gradient(colors: colors), startPoint: startPoint, endPoint: endPoint)
    }
}

我试图根据传递给样式的渐变端点更改我的两个阴影和高光的偏移量,以便内部和外部发光和阴影始终位于按钮的适当两侧。但是,尝试将 switch case 添加到偏移值或函数调用以返回适当的值会产生Closure containing control flow statement cannot be used with result builder 'CommandsBuilder'编译时异常。

有没有什么方法可以根据给样式的 UnitPoint 设置阴影和高光的偏移值,或者我是否必须为每种可能性制作一个按钮样式(这似乎是一个不可行的期望)?

非常感谢任何和所有帮助或建议!

4

1 回答 1

2

Xcode 未能产生真正的错误,这就是他所说的CommandsBuilder.

通常当您遇到此类问题时,请尝试逐块注释您的代码以定位问题。

在这种情况下,如果您评论if .. { } else { }并留下其中的两个部分if(只是为了构建它),Xcode 将能够告诉实际问题


在这种情况下LinearGradient没有init(colors: ...,所以两行

.mask(Circle().fill(LinearGradient(colors: [Color.black, Color.clear], startPoint: startPoint, endPoint: endPoint)))

应替换为:

.mask(Circle().fill(LinearGradient(gradient: Gradient(colors: [Color.black, Color.clear]), startPoint: startPoint, endPoint: endPoint)))

如果您想在修饰符getXoffetInnerShadow的参数处使用下面定义的函数,例如.offset,您应该将返回类型替换为CGFloat,因为这是唯一.offset接受的类型。

于 2021-08-24T04:04:37.547 回答