UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: How do I restrict TextView input to a certain number of characters

Forums > 100 Days of SwiftUI

I have a TextView wrapped in a View (which I wish to use a Component in attempt to creating a pin code entry style widget). I was wondering if there's a way of restricting the input of a TextView to a certain number of characters?

Any pointers would be much appreciated. Current setuip is as follows (please note that the code is very experimental):

import SwiftUI

struct CharacterInputCell: View {

    @State private var textValue: String = ""

    var body: some View {
        TextField("", text: $textValue, onEditingChanged: onEditingChanged(_:), onCommit: onCommit)
        .frame(maxWidth: .infinity, alignment: .center)
        .padding([.trailing, .leading], 10)
        .padding([.vertical], 15)
        .lineLimit(1)
        .multilineTextAlignment(.center)
        .overlay(
            RoundedRectangle(cornerRadius: 6)
                .stroke(Color.red.opacity(0.5), lineWidth: 2)
        )
    }

    func onCommit() {
        print("commit")
    }

    func onEditingChanged(_ changed: Bool) {
        print(changed)
    }
}

struct CharacterInputCell_Previews: PreviewProvider {
    static var previews: some View {
        CharacterInputCell()
    }
}

3      

Hello!

I've found a workaround of limitting an input character count for TextField here on StackOverflow, and tried it in code my self and it works. See updated code.

 class TextBindingManager: ObservableObject {
    @Published var text = "" {
        didSet {
            if text.count > characterLimit && oldValue.count <= characterLimit {
                text = oldValue
            }
        }
    }
    let characterLimit: Int

    init(limit: Int = 1){
        characterLimit = limit
    }
}

struct CharacterInputCell: View {
    @ObservedObject var textBindingManager = TextBindingManager(limit: 1)

    var body: some View {
        TextField("", text: $textBindingManager.text, onEditingChanged: onEditingChanged(_:), onCommit: onCommit)
        .frame(maxWidth: .infinity, alignment: .center)
        .padding([.trailing, .leading], 10)
        .padding([.vertical], 15)
        .lineLimit(1)
        .multilineTextAlignment(.center)
        .overlay(
            RoundedRectangle(cornerRadius: 6)
                .stroke(Color.red.opacity(0.5), lineWidth: 2)
        )
    }

    func onCommit() {
        print("commit")
    }

    func onEditingChanged(_ changed: Bool) {
        print(changed)
    }
}

5      

Not sure if this is 100% efficient but I have been attempting to implement a solution using Combine and it looks something like this:

import SwiftUI
import Combine

struct PassCodeInputCell: View {

    @Binding var value: String

    var body: some View {
        TextField("", text: self.$value)
        .frame(height: 20)
        .frame(maxWidth: .infinity, alignment: .center)
        .padding([.trailing, .leading], 10)
        .padding([.vertical], 15)
        .overlay(
            RoundedRectangle(cornerRadius: 6)
                .stroke(Color.red.opacity(0.5), lineWidth: 2)
        )
        .onReceive(Just(self.value)) { inputValue in
            // With a little help from https://bit.ly/2W1Ljzp
            if inputValue.count > 1 {
                self.value.removeLast()
            }
        }
    }
}

struct PassCodeInputCell_Previews: PreviewProvider {
    static var previews: some View {
        PassCodeInputCell(value: .constant("T"))
    }
}

thoughts, feedback and specially imporvements are very welcome.

6      

Thanks @devraj for your code, it works perfectly comparing to the above one which didn't work with me really don't know why cause it looks logic. Yours is less code and doesn't create a new specific object for each single view, i really like it.

Thanks again.

3      

Thanks @devraj. I also had problems with the Stackoverflow approaches. The Combine approach looks nice. It is reusable as well if you create a custom modifier passing in a text binding and a limit.

Like this at the call site:

@State private var name = ""

...

TextField("", text: $name)
    .limitText($name, length: 30)

4      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.