June 10, 2020

SwiftUI TextField Character Limit

SwiftUI TextField Character Limit

I have written about how to add a character limit to UITextField so I thought that I might as well write a tutorial on how to add a character limit to a SwiftUI TextField.

There are few things that change when doing it for SwiftUI. These changes are mainly due to SwiftUI being declarative, so the state needs to do the processing of data rather than having a delegate method that will control the TextField.

Now that we know that we need to do the processing on the state side of things I can mention that this tutorial will be using combine, specifically Published, ObservableObject and ObservedObject. Luckily these can be very simple to use and for this tutorial they are.

This is what we will be making:

Step 1: Create TextLimiter ObservableObject

The first step that we need to take is to create our TextLimiter class, this will be an ObservableObject which will allow us to Publish values. In particular we will be publishing the text value that will be in the TextField, but we will also publish an informational value so that we know when the limit has been reached.

Add the following class to your project, I have added this into my ContentView file, but you can put it anywhere:

class TextLimiter: ObservableObject {
    private let limit: Int
    
    init(limit: Int) {
        self.limit = limit
    }
    
    @Published var value = ""
    @Published var hasReachedLimit = false
}

What are we doing here? We have a limit property which will store the character limit when we initialise the TextLimiter. This limit will be used later on when we add the logic to prevent the string from being longer than the limit we provide.

We also have two variables that use the @Published property wrapper. The first is value, this will be the value that the TextField displays and hasReachedLimit is a boolean that will be changed when with the logic that I previously mentioned.

Now that we have the base of our class out of the way, we can implement the logic. Update @Publised var value = "" to this:

@Published var value = "" {
    didSet {
        if value.count > self.limit {
            value = String(value.prefix(self.limit))
            self.hasReachedLimit = true
        } else {
            self.hasReachedLimit = false
        }
    }
}

In the above code we are apply our limit to the value. To do this we use a Property Observer. In the above property observer we do a check to see if the count of value is greater than the limit that we provided. If it is, we will assign a prefix of value to value, that prefix will use the limit that we provided to only take the correct amount of characters from the start of the string.

Once we assign that prefix string to value we set hasReachedLimit to true.

Step 2: Use TextLimiter

In my ContentView struct I am going to add the following ObservedObject property:

@ObservedObject var input = TextLimiter(limit: 5)

Here we will initialise the TextLimiter and set the limit to 5. After that I have a the following in the ContentView body:

TextField("Text Input",
          text: $input.value)
    .border(Color.red,
            width: $input.hasReachedLimit.wrappedValue ? 1 : 0 )

Here we can see how everything is being used. We bind the TextField text to $input.value, this will be the value property from TextLimiter. This is all that we need to in order to have the character limit applied, remember the logic for limiting the characters is not done on the view. So if you build and run you should not be able to enter more than 5 characters.

Lastly we use the $input.hasReachedLimit.wrappedValue. For this tutorial I have added a red border and I set the width based on whether the input has reached the limit or not. This is more just to show you how you can use the limit in a different way.

We could change some of the logic in our TextLimiter to allow for a min and max limit. This could let us validate whether a user has the correct number of characters, and if they are within range we can add a green border and if they are out of the range then we add a red border.

Conclusion

Adding a character limit in SwiftUI using TextField is much nicer than using UITextField and its delegate methods.

If you want to see the full source code for this tutorial, you can find it here.