onmyway133 / blog

🍁 What you don't know is what you haven't learned
https://onmyway133.com/
MIT License
675 stars 33 forks source link

How to show suffix text in TextField in SwiftUI #845

Open onmyway133 opened 3 years ago

onmyway133 commented 3 years ago

Suppose we have struct Payment as the state, we declare custom Binding<String> that derives from our state.

struct Payment {
    var amount: Int = 0
}

To show our suffix view, we use .fixedSize(horizontal: true, vertical: false) to constrain our TextField to fit content, and to avoid it to grow outside our frame, we constrain a max limit, like 10_000 in this case. An interesting thing is we divide by 10 to not let the newly typed digit enter if the amount is above our limit

Note also the use of firstTextBaseline in HStack to align baseline

Screenshot 2021-08-24 at 15 25 43
var textField: some View {
    let text = Binding<String>(
        get: {
            state.payment.amount > 0 ? "$\(state.payment.amount)" : ""
        },
        set: { text in
            let text = text.replacingOccurrences(of: "$", with: "")
            let amount = Int(text) ?? 0
            if amount < 10_000 {
                state.payment.amount = amount
            } else {
                state.payment.amount = amount / 10
            }
        }
    )

    return HStack(alignment: .firstTextBaseline, spacing: 0) {
        TextField("$0", text: text)
            .keyboardType(.numberPad)
            .fixedSize(horizontal: true, vertical: false)
            .font(.system(size: 48, weight: .medium, design: .monospaced))
            .foregroundColor(Asset.textPrimary.color)
            .multilineTextAlignment(.center)
            .accentColor(Asset.orange.color)

        if state.payment.frequency == .monthly {
            Text("/month")
                .font(.system(size: 21, weight: .medium, design: .monospaced))
                .foregroundColor(
                    state.payment.amount > 0 ? Asset.textPrimary.color : Asset.textSecondary.color
                )
        }
    }
}