SwiftUI: ViewModifier,其中内容是一个形状

9
以下代码可以正常工作。 所以,我很好...但我想学习ViewModifiers ...所以我的目标是将非更改的内容与动态内容分开,创建一个.cardify()自定义修饰符以调用Shapes视图。
struct SetCard: View {
    
    let pips: Int
    let shape: SetCardShape
    let color: Color
    let shading: Double
    let isSelected: Bool
    
    var body: some View {
        
        ZStack {
            VStack {
                ForEach( 0..<pips ) { _ in
                    ZStack {
                        getShape(self.shape).opacity(self.shading).foregroundColor(self.color)
                        getShape(self.shape).stroke().foregroundColor(self.color)
                    }
                }
            }
            .padding() // for shape in RoundedRect
            RoundedRectangle(cornerRadius: 10).stroke(lineWidth: isSelected ? 3.0 : 1.0).foregroundColor(.orange)
        }
        .scaleEffect(isSelected ? 0.60 : 1.0 )
        .padding() // for spacing between cards 
    }
}

出于学术/学习目的,我想简化这个struct,并使用自定义修饰符将主要内容转换为标准卡片。

只有当我在Cardify ViewModifier struct中注释掉第二个content行时,下面的代码块才能正常工作。所有使用填充形状进行点数渲染的卡牌都可以正常呈现。需要将Shape描边(即非填充)的卡需要在我的Cardify ViewModifer中使用第二个content。

第二个content行产生错误:

类型为Cardify.Content(又名_ViewModifier_Content)的值没有成员foregroundColor

注释掉.foregroundColor()会生成错误:

类型为Cardify.Content(又名_ViewModifier_Content)的值没有成员stroke

struct SetCardWithCardify: View {
    
    let pips: Int
    let shape: SetCardShape
    let color: Color
    let shading: Double
    let isSelected: Bool
    
    var body: some View {
        ZStack {
            getShape(shape)
            .modifier(Cardify(pips: pips, shape: shape, color: color, shading: shading, isSelected: isSelected))
        }
    .scaleEffect(isSelected ? 0.60 : 1.0 )
        .padding() // for spacing between cards 
    }
}


struct Cardify: ViewModifier {
    
    var pips: Int
    var shape: SetCardShape
    var color: Color
    var shading: Double
    var isSelected: Bool
    
    func body(content: Content)  -> some View {
    
        ZStack {
            VStack {
                ForEach( 0..<pips ) { _ in
                    ZStack {
                        content.opacity(self.shading).foregroundColor(self.color)
                        content.stroke().foregroundColor(self.color)
                    }
                }
            }
            .padding() // for shape in RoundedRect
            RoundedRectangle(cornerRadius: 10).stroke(lineWidth: isSelected ? 3.0 : 1.0).foregroundColor(.orange)
        }
    }
}

如果这很重要,以下代码是 getShape() 的源代码,它是 Cardify ViewModifier 中的 content 的源代码。

func getShape(_ shape: SetCardShape ) -> some Shape {
    switch shape {
    case .circle:
        return AnyShape( Circle() )
    case .diamond:
        return AnyShape( SetDiamond() )
    case .squiggle:
        return AnyShape( SetSquiggle() )
    }
}


struct AnyShape: Shape {
    
    func path(in rect: CGRect) -> Path {
        return _path(rect)
    }
    
    init<S: Shape>(_ wrapped: S) {
        _path = { rect in
            let path = wrapped.path(in: rect)
            return path
        }
    }
    private let _path: (CGRect) -> Path
}

Diamond()和Squiggle()是符合Shape协议的结构体,在这些结构体中,从`func path(in rect: CGRect) ->Path`中正确返回路径。
我尝试使用以下方式向下转换第二个内容行:
(content as!Shape)。blah blah blah
这会生成错误:
协议Shape只能用作通用约束,因为它具有Self或相关类型要求。
我还尝试了:
(content as!Path)
这不会生成任何编译时错误,但在执行时会失败,并显示以下错误:
在运行时遇到了问题,请检查您的代码是否在此处存在错误。(指示第二个内容行)。
我该怎么做才能使编译器知道这个内容的类型,以便stroke()和foregroundColor()能够正常工作?

你最终解决了这个问题吗? - derickito
1个回答

4

我不确定你是否能够实现,但你可以使用Shape的扩展来近似实现:

extension Shape {
    func modified() -> some View {
        foregroundColor(Color.secondary.opacity(0.5))
    }
}

// Usage example
struct ContentView: View {
    var body: some View {
        VStack {
            Rectangle().modified()
            Capsule().modified()
        }
    }
}

然而,与视图修饰符不同,您无法访问环境,因此它有一定的限制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接