Home > Blockchain >  How can I return some InsettableShape Protocol in SwiftUI
How can I return some InsettableShape Protocol in SwiftUI

Time:02-11

I have a function which returns some InsettableShape like this:

func test(value: Int) -> some InsettableShape {
    
    if (value == 0) {
        return Circle()
    }
    else if (value == 1) {
        return Capsule()
    }
    else {
        return Rectangle()
    }
    
}

Xcode give an error of:

Function declares an opaque return type, but the return statements in its body do not have matching underlying types

because there is a missing ShapeBuilder or InsettableShapeBuilder wrapper, I cannot make this code work, how can I solve this problem?

CodePudding user response:

Ok, the task is to convert all those different value-types to one single, so we need a non-generic type wrapper confirming to InsettableShape protocol.

Here is a simplified demo of possible approach. Tested with Xcode 13.2 / iOS 15.2

demo

struct Demo_Previews: PreviewProvider {
    static var previews: some View {
        test(value: 0)
            .strokeBorder(Color.red, style: StrokeStyle(lineWidth: 50.0, lineCap: .round, lineJoin: .round))
    }
}

func test(value: Int) -> some InsettableShape {
    if (value == 0) {
        return MyInsettableShape { Circle().trim(from: 0, to: 0.5).path(in: $0) }
    }
    else if (value == 1) {
        return MyInsettableShape { Capsule().path(in: $0) }
    }
    else {
        return MyInsettableShape { Rectangle().path(in: $0) }
    }
}

// Shape independent wrapper - possible, because any shape
// can provide a path for specified region rectangle
struct MyInsettableShape: InsettableShape {
    
    private let base: (CGRect) -> Path
    private let inset: CGFloat
    
    init(base: @escaping (CGRect) -> Path, inset: CGFloat = 0) {
        self.base = base
        self.inset = inset
    }
    
    func inset(by amount: CGFloat) -> Self {
        .init(base: base, inset: amount)
    }
    
    func path(in rect: CGRect) -> Path {
        base(rect.inset(by: .init(top: inset, left: inset, bottom: inset, right: inset)))
    }
}
  • Related