swift 将视图作为参数添加到自定义ViewModifier

3htmauhk  于 2023-10-15  发布在  Swift
关注(0)|答案(2)|浏览(116)

这更像是一个句法问题。我尝试在不使用AnyView的情况下将视图传递到ViewModifier初始化器。
目前,我有一些使用AnyView运行的东西,但我想使用通用的视图语法,因为你会把一个“some view”传递给这个答案中概述的视图:
How to pass one SwiftUI View as a variable to another View struct
我似乎不能让它与ViewModifier工作。
目的(如示例所示)是让修饰符将计算值传递到innerView中。我也很乐意使用@ViewBuilder以某种方式指定innerView属性,因为这可能具有相同的效果。
下面是示例修改器:

struct SampleModifier: ViewModifier {

    let param1: CGFloat
    let innerView:  (CGFloat, CGFloat) -> AnyView
    
    // Assume these are calculated states
    let calculatedParam1: CGFloat = 100
    let calculatedParam2: CGFloat = 100
    
    func body(content: Content) -> some View {
        ZStack {
            HStack {
                Spacer()

                innerView(self.calculatedParam1, self.calculatedParam2)
                    .padding(.leading, 10)
                    .frame(width: param1)
            }
            
            content.frame(width: 100, height: 100)
        }
        
    }
}

其用途:

struct SampleView: View {
    var body: some View {
        Rectangle()
            .modifier(SampleModifier(param1: 150, innerView: { param1, param2 in
                return AnyView(
                    Text("Inner View: \(param1) - \(param2)")
                )
            }))
    }
}
2guxujil

2guxujil1#

你可以使用泛型,比如make innerView返回 some view:

struct SampleModifier<V>: ViewModifier where V: View {
    let param1: CGFloat
    let innerView: (CGFloat, CGFloat) -> V

    ...
}

你不再需要AnyView了:

struct SampleView: View {
    var body: some View {
        Rectangle()
            .modifier(SampleModifier(param1: 150, innerView: { param1, param2 in
                Text("Inner View: \(param1) - \(param2)")
            }))
    }
}

或者,您可以创建View扩展:

extension View {
    func sampleModifier<V>(
        param1: CGFloat,
        innerView: @escaping (CGFloat, CGFloat) -> V
    ) -> some View where V: View {
        modifier(SampleModifier(param1: param1, innerView: innerView))
    }
}

这样使用:

struct SampleView: View {
    var body: some View {
        Rectangle()
            .sampleModifier(param1: 150, innerView: { param1, param2 in
                Text("Inner View: \(param1) - \(param2)")
            })
    }
}
gpnt7bae

gpnt7bae2#

除了@pawello2222的正确答案外,为了满足原始请求:
我也很乐意使用@ViewBuilder以某种方式指定innerView属性,因为这可能具有相同的效果。
只需将@ViewBuilder作为参数属性添加到innerView参数:

extension View {
    func sampleModifier<V>(
        param1: CGFloat,
        @ViewBuilder innerView: @escaping (CGFloat, CGFloat) -> V
    ) -> some View where V: View {
        modifier(SampleModifier(param1: param1, innerView: innerView))
    }
}

相关问题