Skip to content

Instantly share code, notes, and snippets.

@Sidetalker
Last active February 15, 2025 09:30
Show Gist options
  • Save Sidetalker/a9376126ce059803082861eed3a9b481 to your computer and use it in GitHub Desktop.
Save Sidetalker/a9376126ce059803082861eed3a9b481 to your computer and use it in GitHub Desktop.
ProgressBar with masked text in SwiftUI
import SwiftUI
struct ProgressBarConfig {
let height: CGFloat = 50
let width: CGFloat = 300
let cornerRadius: CGFloat = 25
let initialProgress: CGFloat = 0.3
let backgroundColor: Color = Color.gray.opacity(0.3)
let foregroundColor: Color = .blue
let text: String = "Current Streak: 1"
let textSize: CGFloat = 24
let textWeight: Font.Weight = .bold
let textColorOverBar: Color = .white
let textColorOutsideBar: Color = .black
let horizontalPadding: CGFloat = 16
}
struct ProgressMaskText: View {
let config: ProgressBarConfig
@State private var progress: CGFloat
init(config: ProgressBarConfig = ProgressBarConfig()) {
self.config = config
self._progress = State(initialValue: config.initialProgress)
}
var body: some View {
ZStack(alignment: .leading) {
// Background progress bar (gray part)
RoundedRectangle(cornerRadius: config.cornerRadius)
.fill(config.backgroundColor)
.frame(height: config.height)
// Foreground progress bar (colored part)
RoundedRectangle(cornerRadius: config.cornerRadius)
.fill(config.foregroundColor)
.frame(width: config.width * progress, height: config.height)
// Text layers
ZStack {
// Black text (background)
Text(config.text)
.font(.system(size: config.textSize, weight: config.textWeight))
.foregroundColor(config.textColorOutsideBar)
// White text (foreground, masked)
Text(config.text)
.font(.system(size: config.textSize, weight: config.textWeight))
.foregroundColor(config.textColorOverBar)
.mask(
RoundedRectangle(cornerRadius: config.cornerRadius)
.frame(width: config.width * progress - config.horizontalPadding)
.frame(maxWidth: .infinity, alignment: .leading)
)
}
.padding(.horizontal, config.horizontalPadding)
}
.frame(width: config.width)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { value in
progress = min(max(value.location.x / config.width, 0), 1)
}
)
}
}
#Preview {
ProgressMaskText()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment