Enhancing User Experience: Live Character Counting Circle
One lazy Sunday morning, while aimlessly scrolling through Twitter, an experience struck me: the circular animation that fills up as a user types a tweet.
The experience felt engaging; you type, and concurrently witness a live visualization of the characters being entered within a filling circle.
The Journey to Replicate
Inspired by this experience, I delved into reproducing it using Xcode. However, it proved more complex than anticipated initially.
Seeking guidance, I scoured articles on circle fill animations. While I successfully reproduced it using a custom view, adapting the code to suit my specific requirements and ensuring accessibility posed significant challenges.
Determined to simplify the process, I turned to the Apple Developer Documentation and stumbled upon Gauges, introduced in iOS 16.
The Gauge
seemed tailor-made for my needs, as the documentation describes it: "A view that displays a value within a specified range."
Unraveling the User Story
To better grasp the scenario, I envisioned the user's journey while composing a tweet:
- User inputs text
- A visual cue appears as the character limit approaches, signaling 10 characters remaining
- Upon reaching zero characters, a red circle displays negative numbers (0, -1, -2, -3, and so on)
Simplifying the Challenge
My approach aimed for simplicity. Forgoing a custom view, I relied on the built-in Gauge component.
Initially, I experimented within a Playground to develop the character logic before implementing it in my app.
Implementation
Key @State
variables employed:
private let maximumChars: Int = 10
@State private var userInput: String = ""
@State private var value: Int = 0
@State private var isOverMaximumValue: Int?
@State private var tintColor: Color = .blue
@FocusState private var keyboardFocus: Bool
Method for character count calculation:
private func calculRemainingCharacters(
input: String,
maximumCharacters: Int
) {
if input.count < maximumCharacters {
value = input.count
tintColor = .blue
isOverMaximumValue = nil
} else if input.count == maximumCharacters {
tintColor = .red
value = maximumCharacters
isOverMaximumValue = 0
} else {
isOverMaximumValue = input.count - maximumCharacters
}
}
Computed property to inform the user of excessive character count:
private var isZeroOrMore: String {
guard let isOverMaximumValue else { return "" }
return isOverMaximumValue == .zero ? "0" : "-\(isOverMaximumValue)"
}
The view setup:
List {
VStack(alignment: .leading) {
TextField("Write your thoughts", text: $userInput)
.focused($keyboardFocus)
Gauge(value: CGFloat(value), in: 0...CGFloat(maximumChars)) {
Text(isZeroOrMore)
.foregroundStyle(.red)
}
.tint(tintColor)
.gaugeStyle(.accessoryCircularCapacity)
}
}
.onChange(of: userInput) {
calculateRemainingCharacters(input: userInput, maximumCharacters: maximumChars)
}
You can clone and compile for watch what's the result or watch the readme on the project's repository
Thank you for reading!
Feel free to reach out if you have any questions.