Home > Back-end >  change the fontsize of the decimal number in Swift/ SwiftUI
change the fontsize of the decimal number in Swift/ SwiftUI

Time:09-16

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
This is the result I get This is the 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)

enter image description here

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:

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
    }
}
  • Related