So i need to make the decimal places smaller than the actual number i will show you what i mean below.
this is the code i have:
import SwiftUI
struct BalanceDetailsView: View {
//MARK: - PROPERTIES
var balance: Float
var balanceString: String {
return balance.formattedWithSeparator
}
//MARK: - BODY
var body: some View {
VStack{
HStack{
Text(balanceString)
.font(.custom(K.fonts.gilroyBold, size: 24))
.multilineTextAlignment(.center)
.padding(.top)
}//:VSTACK
}//:HSTACK
}
}
struct BalanceDetailsView_Previews: PreviewProvider {
static var previews: some View {
BalanceDetailsView(balance: 43678)
.previewLayout(.sizeThatFits)
}
}
//Formatter extension i used to get this code
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// minimum decimal digit, eg: to display 2 as 2.00
formatter.minimumFractionDigits = 2
// maximum decimal digit, eg: to display 2.5021 as 2.50
formatter.maximumFractionDigits = 2
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String { Formatter.withSeparator.string(for: self) ?? "" }
}
Result I get | Result I need |
---|---|
CodePudding user response:
When you know exact format of your string, like in this case minimum string length will be 4("0.00") , you can safely use dropLast
and dropFirst
.
I suggest moving 2
to priceFractionDigits
constant to reduce constants usage in your code.
Then you can use string concatenation, it'll align Text
by baseline.
struct BalanceText: View {
var balance: Float
var balanceString: String {
return balance.formattedWithSeparator
}
var body: some View {
Text(balanceString.dropLast(priceFractionDigits))
.font(.system(size: 24))
Text(balanceString.dropFirst(balanceString.count - priceFractionDigits))
.font(.system(size: 18))
}
}
private let priceFractionDigits = 2
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// minimum decimal digit, eg: to display 2 as 2.00
formatter.minimumFractionDigits = priceFractionDigits
// maximum decimal digit, eg: to display 2.5021 as 2.50
formatter.maximumFractionDigits = priceFractionDigits
return formatter
}()
}
Usage
BalanceText(balance: balance)
CodePudding user response:
Here is an example using the new AttributedString
in SwiftUI 3 (iOS 15, macOS 12 etc)
var balanceString: AttributedString {
var attributedString = AttributedString(balance.formattedWithSeparator)
guard let separator = Formatter.withSeparator.decimalSeparator else { return attributedString }
if let range = attributedString.range(of: separator) {
attributedString[attributedString.startIndex...attributedString.index(beforeCharacter: range.lowerBound)]
.font = Font.largeTitle
attributedString[attributedString.index(afterCharacter: range.lowerBound)..<attributedString.endIndex]
.font = Font.caption
}
return attributedString
}
I used some built in font styles here but that should be easy to replace. Also note that since we set the .font
attribute here it should be removed from Text
CodePudding user response:
You can concatenate Text
together with the
operator.
I slightly change the way you use NumberFormatter
, so it's split by the correct decimal character for the locale.
struct BalanceDetailsView: View {
private let wholeNumberPart: String
private let decimalNumberPart: String
init(balance: Double) {
(wholeNumberPart, decimalNumberPart) = balance.formattedSplittingBySeparator
}
var body: some View {
Text(wholeNumberPart).font(.system(size: 24))
Text(decimalNumberPart).font(.system(size: 16))
}
}
extension Numeric {
var formattedSplittingBySeparator: (whole: String, decimal: String) {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
let str = formatter.string(for: self) ?? "0\(formatter.decimalSeparator!)00"
let split = str.components(separatedBy: formatter.decimalSeparator)
let whole = (split.first ?? "0") formatter.decimalSeparator
let decimal = split.count == 2 ? split[1] : "00"
return (whole: whole, decimal: decimal)
}
}
Usage:
BalanceDetailsView(balance: 43678)
Result:
CodePudding user response:
You could split the string by the decimal separator and display the parts in a zero-spacing HStack
.
struct BalanceView : View {
let balance : Float
var body: some View {
let components = balance
.formattedWithSeparator
.components(separatedBy: Formatter.withSeparator.decimalSeparator)
HStack(alignment: .firstTextBaseline, spacing: 0) {
Text(components[0])
if components.count > 1 {
Text(".")
Text(components[1])
.font(.title)
}
}
.font(.largeTitle)
.multilineTextAlignment(.center)
.padding(.top)
}
}
Replace the fonts with your custom fonts
In your environment you could use it
struct BalanceDetailsView: View {
//MARK: - PROPERTIES
var balance: Float
//MARK: - BODY
var body: some View {
VStack{
BalanceView(balance: balance)
}//:VSTACK
}
}