Last active
February 15, 2025 09:30
-
-
Save Sidetalker/a9376126ce059803082861eed3a9b481 to your computer and use it in GitHub Desktop.
ProgressBar with masked text in SwiftUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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