iosswiftswiftuiipadosswiftui-text

How to create an enum based .textStyle(.title) modifier for Text(...) components in SwiftUI?


I want to implement a modifier setting for Texts in a similar way as it already exists for Buttons.

Aka:

Button( ... )
   .buttonStyle(.plain) // <-- .plain and not PlainStyle()

Problem Of course I cannot use an opaque which is not really the same. If it would be a View I could wrap it in an AnyView but for ViewModifiers I need another solution.

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

Maybe it is a bonus idea to have something like a .textStyle(.title) modifier but in my eyes, it could reduce my code to write enormously.

Source


struct TitleStyle: ViewModifier {
    func body(content: Content) -> some View {
      ...
    }
}

struct BodyStyle: ViewModifier {
    func body(content: Content) -> some View {
      ...
    }
}


enum TextStyle {
    
    case title
    case body

    // Error: Function declares an opaque return type, 
    // but the return statements in its body do not have matching underlying types
    var modifier: some ViewModifier {
        switch self
        {
        case .title: return TitleStyle()
        case .body: return BodyStyle()
        }
    }
}

Solution

  • It works different way. As all this is around generics we need to restrict declarations for known concrete types.

    So, having TitleStyle and BodyStyle declared and concrete, we can specify

    extension ViewModifier where Self == TitleStyle {
        static var title: TitleStyle { TitleStyle() }
    }
    
    extension ViewModifier where Self == BodyStyle {
        static var body: BodyStyle { BodyStyle() }
    }
    

    and then declare extension to use above like

    extension View {
        func textStyle<Style: ViewModifier>(_ style: Style) -> some View {
            ModifiedContent(content: self, modifier: style)
        }
    }
    

    so as a result we can do as demo

    struct Demo_Previews: PreviewProvider {
        static var previews: some View {
            Text("Demo")
                .textStyle(.title)
        }
    }
    

    demo

    Prepared with Xcode 13.4 / iOS 15.5

    Test module in GitHub