Skip to content

Instantly share code, notes, and snippets.

@badrinathvm
Created June 18, 2024 00:25
Show Gist options
  • Save badrinathvm/fabb741cb35b98ec2c2eed3776217371 to your computer and use it in GitHub Desktop.
Save badrinathvm/fabb741cb35b98ec2c2eed3776217371 to your computer and use it in GitHub Desktop.
Providing option for Custom Style View Modifier
import SwiftUI
// MARK: 2. Create view style protocol
protocol CardStyle {
associatedtype Body: View
typealias Configuration = CardStyleConfiguration
func makeBody(configuration: Self.Configuration) -> Self.Body
}
// MARK: 3. Create style configuration
struct CardStyleConfiguration {
/// A type-erased content of a `Card`.
struct Label: View {
init<Content: View>(content: Content) {
body = AnyView(content)
}
var body: AnyView
}
let label: CardStyleConfiguration.Label
}
// MARK: 4. Implement base view styles
struct DefaultCardStyle: CardStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.title)
.padding()
.background(RoundedRectangle(cornerRadius: 16).strokeBorder())
}
}
struct GradientCardStyle: CardStyle {
let gradient = AngularGradient(
gradient: Gradient(colors: [Color.red, Color.green, Color.blue]),
center: .center)
func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.title)
.padding()
.background(RoundedRectangle(cornerRadius: 16).stroke(gradient, lineWidth: 1))
}
}
// MARK: 6. Setup style environment (key + environment value + style eraser)
struct AnyCardStyle<S: CardStyle>: CardStyle {
private var _makeBody: (Configuration) -> S.Body
init(style: S) {
_makeBody = { configuration in
style.makeBody(configuration: configuration)
}
}
func makeBody(configuration: Configuration) -> S.Body {
_makeBody(configuration)
}
}
struct CardStyleKey: EnvironmentKey {
static var defaultValue = AnyCardStyle(style: DefaultCardStyle())
}
extension EnvironmentValues {
var cardStyle: AnyCardStyle<DefaultCardStyle> {
get { self[CardStyleKey.self] }
set { self[CardStyleKey.self] = newValue }
}
}
// MARK: 7. Define `.xxxStyle(_:)` convenience view modifier
extension View {
func cardStyle(style: any CardStyle = DefaultCardStyle()) -> some View {
self.modifier(CardModifier(style: style))
}
}
// MARK: 8. Update view to take advantage of environment style
struct CardModifier: ViewModifier {
var style: any CardStyle
public func body(content: Content) -> some View {
AnyView(style
.makeBody(
configuration: CardStyleConfiguration(
label: CardStyleConfiguration.Label(content: content)
)
)
)
}
}
// MARK: 9. Enjoy :)
struct TestView: View {
var body: some View {
Button {
} label: {
Text("Hello")
}
.cardStyle(style: GradientCardStyle())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment