我们给 Badge 添加自定义样式, 效果图
1.定义协议
protocol BadgeStyle {
associatedtype Body: View
@ViewBuilder func makeBody(_ label: AnyView) -> Body
}
2.默认样式
struct DefaultBadgeStyle: BadgeStyle {
var color: Color = .red
func makeBody(_ label: AnyView) -> some View {
label
.font(.caption)
.foregroundStyle(.white)
.padding(.horizontal, 5)
.padding(.vertical, 2)
.background(
Capsule(style: .continuous)
.fill(color)
)
}
}
3.带阴影和边框的样式
struct FancyBadgeStyle: BadgeStyle {
var background: some View {
ZStack {
ContainerRelativeShape()
.fill(Color.red)
.overlay {
ContainerRelativeShape()
.fill(LinearGradient(colors: [.white, .clear], startPoint: .top, endPoint: .center))
}
ContainerRelativeShape()
.stroke(.white, lineWidth: 2.0)
.shadow(radius: 2.0)
}
}
func makeBody(_ label: AnyView) -> some View {
label
.font(.caption)
.foregroundStyle(.white)
.padding(.horizontal, 5)
.padding(.vertical, 2)
.background(background)
.containerShape(Capsule(style: .continuous))
}
}
4.通过自定义环境变量去修改 badgeStyle
enum BadgeStyleKey: EnvironmentKey {
static var defaultValue: any BadgeStyle = DefaultBadgeStyle()
}
extension EnvironmentValues {
var badgeStyle: any BadgeStyle {
get {
self[BadgeStyleKey.self]
}
set {
self[BadgeStyleKey.self] = newValue
}
}
}
5.用 modifier 使用对齐方式和样式
struct OverlayBadge<BadgeLable: View>: ViewModifier {
var alignment: Alignment = .topTrailing
var label: BadgeLable
@Environment(\.badgeStyle) var badgeStyle
func body(content: Content) -> some View {
content
.overlay(alignment: alignment) {
AnyView( badgeStyle.makeBody(AnyView(label)))
.alignmentGuide(alignment.horizontal, computeValue: { dimension in
dimension[HorizontalAlignment.center]
})
.alignmentGuide(alignment.vertical, computeValue: { dimension in
dimension[VerticalAlignment.center]
})
}
}
}
6. 方便 View 使用, 添加扩展
extension View {
func badgeStyle(_ style: any BadgeStyle) -> some View {
environment(\.badgeStyle, style)
}
func badge<V: View>(alignment: Alignment = .topTrailing, @ViewBuilder _ content: () -> V) -> some View {
modifier(OverlayBadge(alignment: alignment, label: content()))
}
}
7. 方便设置 style
extension BadgeStyle where Self == FancyBadgeStyle {
static var fancy: FancyBadgeStyle { FancyBadgeStyle()
}
}
8.使用
ZStack {
Color.teal
VStack {
Text("SwiftUI")
.badge {
Text(100, format: .number)
}
}
.badgeStyle(.fancy)
}