2

Sorry if the question has been already answered. I'm new to Swift, and I want to create a simple fixed-size TextField for one-time password:

TextField("******", text: self.$otp)
                    .padding()
                    .textContentType(.oneTimeCode)
                    .keyboardType(.numberPad)

I was hoping to find a configuration parameter similar to <input size="6"/> in HTML so that the engine would automatically compute the TextField's size for N characters.

Is there a simple solution to this without jumping through hoops like using ZStacks and spawning N text fields as I saw some enthusiasts were suggesting?

andbi
  • 4,426
  • 5
  • 45
  • 70
  • 2
    The width of 6 characters depends on what the 6 characters are. Without turning on monospacedDigit, even digits aren't a consistent width. Some characters are extremely wide (﷽ is one "character") and some are very narrow (i), so what would you want the width to be based on? – Rob Napier Jun 28 '21 at 16:48
  • See this thread: https://stackoverflow.com/a/68167518/14733292 – Raja Kishan Jun 28 '21 at 17:12
  • @RobNapier the backend is sending 6 ASCII digits. Assuming I turned on the `monospacedDigit`, will it be possible and how? Should I precompute the size of a single character and multiply it by N? – andbi Jun 28 '21 at 17:58
  • @RajaKishan thanks, but that's about max length whereas I need a fixed size solution. – andbi Jun 28 '21 at 18:01
  • @andbi use this extension as I mention in the previous comment and set ```.fixedSize()``` to text field as mention in the answere. – Raja Kishan Jun 28 '21 at 18:06
  • 2
    Yes; work out the size you believe it will be, and set the width to what you want. Be careful of dynamic text, which could resize your font if it's not locked to a specific size. If you need to handle that, see https://stackoverflow.com/questions/65710895/is-there-a-way-in-swiftui-to-detect-if-a-user-has-larger-text-size-enabled for how to know the size, or you can use a GeometryReader to work out the correct size dynamically, but it's a lot more work. (If you need that, let me know; I'll write it up.) – Rob Napier Jun 28 '21 at 18:10

2 Answers2

3

Use a fixed size TextField.

TextField("******", text: $text).fixedSize()
mahan
  • 12,366
  • 5
  • 48
  • 83
  • 3
    I'm going to go out on a limb and say that is not what he is looking for. https://developer.apple.com/documentation/swiftui/text/fixedsize() – xTwisteDx Jun 28 '21 at 17:18
  • Tried that, the field is growing as user types. – andbi Jun 28 '21 at 17:52
  • I'm a bit surprised, but this actually is the correct approach. I didn't expect it to work. The problem is that `*` is smaller than a digit. If you make the placeholder text `888888` and assign a monospacedDigit Font, this approach absolutely works. I was not expecting that… (if you assign a fixed-width font, this would work as well) As a practical matter, if you change the placeholder text to 8 *s rather than 6, it will also "work" – Rob Napier Jun 28 '21 at 18:17
  • @RobNapier you're right, it works, I was testing with empty placeholder, my bad. – andbi Jun 28 '21 at 18:22
  • I think Menlo is available on iPhone, in which case adding `.font(Font.custom("Menlo", size: 15)).fixedSize()` will make this work, at the cost of using a specific font. – Rob Napier Jun 28 '21 at 18:23
  • @andbi Didn't this help? – mahan Jun 30 '21 at 10:57
  • @mahan Thanks, this did help, I had to limit the max input length by utilizing the `onChange(of:perform:)` method as someone suggested in a comment. – andbi Jun 30 '21 at 12:06
  • 1
    @andbi please accept this answer, it's a great one, meaning: click the checkmark – Bart van Kuik Jul 01 '21 at 16:11
0

you can use frame for such tasks:

TextField(title, text: binding).frame(height: 40)

or

TextField(title, text: binding).frame(width: 40)
nemelianov
  • 911
  • 1
  • 7
  • 15