amin89
amin89

Reputation: 437

SwiftUI example for autocompletion

I'm a SwiftUI beginner. I have an array of "values" provided by an API and what I want is to make autocompletion when we tap characters in a "textfield". Can you please provide me an example of code for SwiftUI which can do this stuff ?

What I mean by autocompletion is this :

enter image description here

I have my own values and not those provided by google such here;

thx

Upvotes: 1

Views: 8714

Answers (2)

FrugalResolution
FrugalResolution

Reputation: 655

Filter a list with values, easily with the build in .searchable function:

    List {
        ForEach(searchResults, id: \.self) { name in
            Text(name)
        }
    }
    .searchable(text: $textField, placement: .navigationBarDrawer(displayMode: .always))

The value for `placement displays the searchbar always.

Also add a filter variable:

var searchResults: [String] {
    if textField.isEmpty {
        return sectionNames
    } else {
        return sectionNames.filter { $0.lowercased().contains(textField.lowercased()) }
    }
}

Of course don't miss out the textFieldInput:

@State var textField: String = ""

Source: Hacking with Swift

Upvotes: 1

Simon
Simon

Reputation: 1850

The code from this repository used: https://github.com/simonloewe/TextFieldInputPrediction

And modified so the predictions are returned as a list like this:

//
//  ContentView.swift
//  StackOverflow
//
//  Created by Simon Löwe on 04.04.20.
//  Copyright © 2020 Simon Löwe. All rights reserved.
//

import SwiftUI

struct ContentView: View {

    @State var textFieldInput: String = ""
    @State var predictableValues: Array<String> = ["First", "Second", "Third", "Fourth"]
    @State var predictedValue: Array<String> = []

    var body: some View {
        VStack(alignment: .leading){
            Text("Predictable Values: ").bold()

            HStack{
                ForEach(self.predictableValues, id: \.self){ value in
                    Text(value)
                }
            }

            PredictingTextField(predictableValues: self.$predictableValues, predictedValues: self.$predictedValue, textFieldInput: self.$textFieldInput)
            .textFieldStyle(RoundedBorderTextFieldStyle())

            // This is the only modification from the example in the repository
            List() {
                ForEach(self.predictedValue, id: \.self){ value in
                    Text(value)
                }
            }

        }.padding()
    }
}


/// TextField capable of making predictions based on provided predictable values
struct PredictingTextField: View {

    /// All possible predictable values. Can be only one.
    @Binding var predictableValues: Array<String>

    /// This returns the values that are being predicted based on the predictable values
    @Binding var predictedValues: Array<String>

    /// Current input of the user in the TextField. This is Binded as perhaps there is the urge to alter this during live time. E.g. when a predicted value was selected and the input should be cleared
    @Binding var textFieldInput: String

    /// The time interval between predictions based on current input. Default is 0.1 second. I would not recommend setting this to low as it can be CPU heavy.
    @State var predictionInterval: Double?

    /// Placeholder in empty TextField
    @State var textFieldTitle: String?

    @State private var isBeingEdited: Bool = false

    init(predictableValues: Binding<Array<String>>, predictedValues: Binding<Array<String>>, textFieldInput: Binding<String>, textFieldTitle: String? = "", predictionInterval: Double? = 0.1){

        self._predictableValues = predictableValues
        self._predictedValues = predictedValues
        self._textFieldInput = textFieldInput

        self.textFieldTitle = textFieldTitle
        self.predictionInterval = predictionInterval
    }

    var body: some View {
        TextField(self.textFieldTitle ?? "", text: self.$textFieldInput, onEditingChanged: { editing in self.realTimePrediction(status: editing)}, onCommit: { self.makePrediction()})
    }

    /// Schedules prediction based on interval and only a if input is being made
    private func realTimePrediction(status: Bool) {
        self.isBeingEdited = status
        if status == true {
            Timer.scheduledTimer(withTimeInterval: self.predictionInterval ?? 1, repeats: true) { timer in
                self.makePrediction()

                if self.isBeingEdited == false {
                    timer.invalidate()
                }
            }
        }
    }

    /// Capitalizes the first letter of a String
    private func capitalizeFirstLetter(smallString: String) -> String {
        return smallString.prefix(1).capitalized + smallString.dropFirst()
    }

    /// Makes prediciton based on current input
    private func makePrediction() {
        self.predictedValues = []
        if !self.textFieldInput.isEmpty{
            for value in self.predictableValues {
                if self.textFieldInput.split(separator: " ").count > 1 {
                    self.makeMultiPrediction(value: value)
                }else {
                    if value.contains(self.textFieldInput) || value.contains(self.capitalizeFirstLetter(smallString: self.textFieldInput)){
                        if !self.predictedValues.contains(String(value)) {
                            self.predictedValues.append(String(value))
                        }
                    }
                }
            }
        }
    }

    /// Makes predictions if the input String is splittable
    private func makeMultiPrediction(value: String) {
        for subString in self.textFieldInput.split(separator: " ") {
            if value.contains(String(subString)) || value.contains(self.capitalizeFirstLetter(smallString: String(subString))){
                if !self.predictedValues.contains(value) {
                    self.predictedValues.append(value)
                }
            }
        }
    }
}

Provides the following outcome:

enter image description here

Tested on Version 11.5 and iOS 13.5

Upvotes: 7

Related Questions