Как проверить, когда изменяется UITextField?

291

Я пытаюсь проверить, когда изменяется текстовое поле, эквивалентно функции, используемой для textView - textViewDidChangeдо сих пор я сделал это:

  func textFieldDidBeginEditing(textField: UITextField) {
        if self.status.text == "" && self.username.text == "" {
            self.topRightButton.enabled = false
        } else {   
            self.topRightButton.enabled = true
        }
    }

Какой тип работает, но topRightButtonон включается, как только текстовое поле нажимается, я хочу, чтобы оно было включено только тогда, когда текст введен на самом деле?

boraseoksoon
источник

Ответы:

740

СВИФТ

Swift 4.2

textfield.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)

и

@objc func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 3 & swift 4.1

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)

и

func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 2.2

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)

и

func textFieldDidChange(textField: UITextField) {
    //your code
}

Objective-C

[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

и метод textFieldDidChange является

-(void)textFieldDidChange :(UITextField *) textField{
    //your code
}
Фавад Масуд
источник
Это терпит крах для меня, и я не понимаю почему.
Леви Робертс
1
Проверено несколько раз. Делегат устанавливается непосредственно перед этим внутри viewDidLoad. Действие буква за буквой то же самое. Приложение вылетает, как только нажимается кнопка клавиатуры. Изменить: понял это! Отсутствует точка с запятой внутри действия. Я предположил, что оно должно совпадать с именем функции.
Леви Робертс
@FawadMasud теперь это ничего не делает в Swift 2.0 на iOS 9 с XCode 7, не рекомендуется ли это или вы знаете, как это исправить?
Коди Уивер
1
@bibscy да, вы должны просмотреть все текстовые поля внутри представления.
Фавад Масуд
1
Для Swift 4.2 это: Texttfield.addTarget (self, action: #selector (ViewControllerr.textFieldDidChange (_ :)), для: UIControl.Event.editingChanged)
Выход
129

Вы можете сделать это соединение в конструкторе интерфейсов.

  1. В раскадровке щелкните редактор-помощник вверху экрана (два кружка посередине). Помощник редактора выбран

  2. Ctrl + клик по текстовому полю в конструкторе интерфейсов.

  3. Перетащите из EditingChanged внутрь вашего класса контроллера представления в представлении помощника. Создание связи

  4. Назовите свою функцию (например, «textDidChange») и нажмите «Подключиться». Функция именования

rmooney
источник
3
Это отличное решение, особенно если вы имеете дело с UITextField в tableViewCell, который управляется отдельным источником данных. Этот подход позволяет viewController отвечать напрямую (таким образом, источник данных не должен отвечать и делегировать действие).
wuf810
1
Отлично - простое решение раздражающей проблемы. Конечно, вы можете связать несколько
Джереми Эндрюс
1
Вероятно, лучший ответ, чем выше, потому что устранение добавления @objc func.
Мэтью Брэдшоу,
Хорошая идея, я использую событие DidEndEditing
Puji Wahono
Это лучшее решение. Спасибо @rmooney!
Джонатан
63

Swift 5.0

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: .editingChanged)

и метод обработки:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 4.0

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: UIControlEvents.editingChanged)

и метод обработки:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 3.0

textField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged)

и метод обработки:

func textFieldDidChange(textField: UITextField) { 

}
Роберт
источник
29

То, как я справился с этим до сих пор: в UITextFieldDelegate

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    // text hasn't changed yet, you have to compute the text AFTER the edit yourself
    let updatedString = (textField.text as NSString?)?.stringByReplacingCharactersInRange(range, withString: string)

    // do whatever you need with this updated string (your code)


    // always return true so that changes propagate
    return true
}

Версия Swift4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
    return true
}
Vinzzz
источник
1
Это не будет вызвано, когда текстовое поле пусто и пользователь нажимает клавишу Backspace.
Мэтью Митчелл
14

Свифт 3

 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(sender:)), for: UIControlEvents.editingChanged)
Алессандро Маттиуцци
источник
7

Swift 3.0.1+ (некоторые другие ответы swift 3.0 не актуальны)

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: UIControlEvents.editingChanged)

func textFieldDidChange(_ textField: UITextField) {

}
aviran
источник
6

textField (_: shouldChangeCharactersIn: replaceString :) работал для меня в Xcode 8, Swift 3, если вы хотите проверить каждое нажатие клавиши.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    // Whatever code you want to run here.
    // Keep in mind that the textfield hasn't yet been updated,
    // so use 'string' instead of 'textField.text' if you want to
    // access the string the textfield will have after a user presses a key

    var statusText = self.status.text
    var usernameText = self.username.text

    switch textField{
    case self.status:
        statusText = string
    case self.username:
        usernameText = string
    default:
        break
    }

    if statusText == "" && usernameText == "" {
        self.topRightButton.enabled = false
    } else {   
        self.topRightButton.enabled = true
    }

    //Return false if you don't want the textfield to be updated
    return true
}
radthemad4
источник
5

Swift 4

Соответствует UITextFieldDelegate .

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // figure out what the new string will be after the pending edit
    let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)

    // Do whatever you want here


    // Return true so that the change happens
    return true
}
drewster
источник
4

Вы можете использовать этот метод делегата из UITextFieldDelegate. Он срабатывает при каждой смене персонажа.

(Objective C) textField:shouldChangeCharactersInRange:replacementString:
(Swift) textField(_:shouldChangeCharactersInRange:replacementString:)

Однако ЭТО ТОЛЬКО ОСТАЕТСЯ ПЕРЕД изменениями (действительно, изменение будет сделано, только если вы вернете истину отсюда).

Абубакр Дар
источник
1
Как это должно быть написано, поскольку я также попробовал этот метод и пришел к тому же решению, где оно меняется только после активации textField, а не после того, как текст действительно изменится ??
Когда вы реализуете вышеупомянутый метод делегата, он срабатывает каждый раз, когда вы изменяете свой текст. Вам нужно только добавить этот код, self.textfield.delegate = self
Abubakr Dar
Для меня этот метод не работал, потому что вы не могли проверить, было ли текстовое поле пустым внутри метода. Прежде всего потому, что он возвращает истину / ложь в зависимости от того, ЕСЛИ текстовое поле может измениться. Таким образом, событие запускается ДО того, как текстовое поле получит шанс стать пустым.
Леви Робертс
@LeviRoberts, у вас есть ссылка на текстовое поле внутри этого метода. Таким образом, вы можете проверить, является ли textfield.text пустым.
Абубакр Дар
Вы, кажется, не понимаете. Когда он пуст, .isEmptyметод не приравнивается к true, пока ПОСЛЕ того, как этот метод не сможет вернуть true; сообщить приложению, что текстовое поле должно измениться.
Леви Робертс
3

Может быть, использовать RxSwift?

необходимость

pod 'RxSwift',    '~> 3.0'
pod 'RxCocoa',    '~> 3.0'

добавить импорт очевидно

import RxSwift
import RxCocoa

Так у тебя есть textfield : UITextField

let observable: Observable<String?> = textField.rx.text.asObservable()
observable.subscribe(
            onNext: {(string: String?) in
                print(string!)
        })

У вас есть 3 других метода ..

  1. OnError
  2. OnCompleted
  3. onDisposed
  4. onNext
marlonpya
источник
Чтобы получать только события реальных изменений, а не также, когда текстовое поле стало первым респондентом, вы должны использовать DifferentUntilChanged для текста.
RealNmae
1

Swift 4

textField.addTarget(self, action: #selector(textIsChanging), for: UIControlEvents.editingChanged)

@objc func textIsChanging(_ textField:UITextField) {

 print ("TextField is changing")

}

Если вы хотите внести изменения после того, как пользователь полностью ввел данные (они будут вызваны, когда пользователь отклонит клавиатуру или нажмете клавишу ввода).

textField.addTarget(self, action: #selector(textDidChange), for: UIControlEvents.editingDidEnd)

 @objc func textDidChange(_ textField:UITextField) {

       print ("TextField did changed") 
 }
Anamika
источник
1
txf_Subject.addTarget(self, action:#selector(didChangeFirstText), for: .editingChanged)

@objc func didChangeText(textField:UITextField) {
    let str = textField.text
    if(str?.contains(" "))!{
        let newstr = str?.replacingOccurrences(of: " ", with: "")
        textField.text = newstr
    }
}

@objc func didChangeFirstText(textField:UITextField) {
    if(textField.text == " "){
        textField.text = ""
    }
}
Йогеш Тандель
источник
1

Вы должны следовать этим шагам:

  1. Сделать ссылку на аутлет на текстовое поле
  2. AssignUITextFieldDelegate для класса контроллера
  3. Настройте yourTextField.delegate
  4. Реализуйте любую функцию, которая вам нужна

Образец кода:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var yourTextFiled : UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        yourTextFiled.delegate = self
    }


    func textFieldDidEndEditing(_ textField: UITextField) {
        // your code
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        // your code
    }

    .
    .
    .
}
M.Hazara
источник
0

Вот как вы можете добавить textField text change listenerиспользование Swift 3 :

Объявите свой класс как UITextFieldDelegate

override func viewDidLoad() {
    super.viewDidLoad()

    textField.delegate = self

    textField.addTarget(self, action: #selector(UITextFieldDelegate.textFieldShouldEndEditing(_:)), for: UIControlEvents.editingChanged)
}

Затем просто традиционно добавьте функцию textFieldShouldEndEditing:

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // do stuff
        return true 
}
Codetard
источник
0

Swift 4.2

напишите это в viewDidLoad

// to detect if TextField changed
TextField.addTarget(self, action: #selector(textFieldDidChange(_:)),
                                   for: UIControl.Event.editingChanged)

написать это за пределами viewDidLoad

@objc func textFieldDidChange(_ textField: UITextField) {
    // do something
}

Вы можете изменить событие с помощью UIControl.Event.editingDidBegin или того, что вы хотите обнаружить.

гениальность
источник
0

На всякий случай, если вы заинтересованы в решении SwiftUI, это работает для меня:

 TextField("write your answer here...",
            text: Binding(
                     get: {
                        return self.query
                       },
                     set: { (newValue) in
                        self.fetch(query: newValue) // any action you need
                                return self.query = newValue
                      }
            )
  )

Я должен сказать, что это не моя идея, я прочитал это в этом блоге: привязка SwiftUI: очень простой трюк

abanet
источник
0

В случае, если невозможно связать addTarget с вашим UITextField, я советую вам связать один из них, как предложено выше, и вставить код для выполнения в конце метода shouldChangeCharactersIn.

nameTextField.addTarget(self, action: #selector(RegistrationViewController.textFieldDidChange(_:)), for: .editingChanged)

@objc func textFieldDidChange(_ textField: UITextField) {
    if phoneNumberTextField.text!.count == 17 && nameTextField.text!.count > 0 {
        continueButtonOutlet.backgroundColor = UIColor(.green)
    } else {
        continueButtonOutlet.backgroundColor = .systemGray
    }
}

И в вызове следует изменитьCharactersIn func.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    guard let text = textField.text else {
        return true
    }
    let lastText = (text as NSString).replacingCharacters(in: range, with: string) as String

    if phoneNumberTextField == textField {
        textField.text = lastText.format("+7(NNN)-NNN-NN-NN", oldString: text)
        textFieldDidChange(phoneNumberTextField)
        return false
    }
    return true
}
Степан Варткинаян
источник
0

Теперь на iOS13 + доступен метод делегата UITextField.

optional func textFieldDidChangeSelection(_ textField: UITextField)
JP Aquino
источник
-1

Свифт 4

В viewDidLoad ():

    //ADD BUTTON TO DISMISS KEYBOARD

    // Init a keyboard toolbar 
    let toolbar = UIView(frame: CGRect(x: 0, y: view.frame.size.height+44, width: view.frame.size.width, height: 44))
    toolbar.backgroundColor = UIColor.clear

    // Add done button
    let doneButt = UIButton(frame: CGRect(x: toolbar.frame.size.width - 60, y: 0, width: 44, height: 44))
    doneButt.setTitle("Done", for: .normal)
    doneButt.setTitleColor(MAIN_COLOR, for: .normal)
    doneButt.titleLabel?.font = UIFont(name: "Titillium-Semibold", size: 13)
    doneButt.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside)
    toolbar.addSubview(doneButt)

    USDTextField.inputAccessoryView = toolbar

Добавьте эту функцию:

    @objc func dismissKeyboard() {
      //Causes the view (or one of its embedded text fields) to resign the first responder status.
      view.endEditing(true)
    }
ноль
источник
-1

создать новый пользовательский класс MaterialTextfield.swift

class MaterialTextfield: UITextField,UITextFieldDelegate {

var bottomBorder = UIView()
var shouldShowEditing = false

override func awakeFromNib() {

    // Setup Bottom-Border

    self.delegate = self
    self.translatesAutoresizingMaskIntoConstraints = false

    bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1) // Set Border-Color
    bottomBorder.translatesAutoresizingMaskIntoConstraints = false

    addSubview(bottomBorder)

    bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
    bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set Border-Strength

}
@IBInspectable var hasError: Bool = false {
    didSet {
        if (hasError) {
            bottomBorder.backgroundColor = UIColor.red//error color
        } else {
            bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1)//passive color
        }

    }
}
@IBInspectable var showEditing: Bool = false{
    didSet {
        if (showEditing) {
            bottomBorder.backgroundColor = UIColor(rgb: 0x56B5CA)//active color
        } else {
            bottomBorder.backgroundColor = UIColor(rgb: 0xE2DCD1)//passive color
        }

    }

}

func textFieldDidBeginEditing(_ textField: UITextField) {//listen to on edit event
    showEditing = !self.showEditing
}
func textFieldDidEndEditing(_ textField: UITextField) {//listen to on end edit event
    showEditing = !self.showEditing
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {//listen to return button event
    textField.resignFirstResponder() // return button will close keyboard
    return true
}

}
Мухаммед Асираф
источник
При всем уважении, это ужасное решение. Он просто хочет проверить UITextField, обновил ли a свое значение - зачем создавать слишком сложный класс для решения этой простой проблемы?
Гильерме Матуелла
@GuilhermeMatuella - это больше интерфейсный код, чтобы пользователь знал, является ли поле обязательным и заполненным. Это другой подход к решению той же проблемы. это в основном мои заказные активы
Мухаммед Асираф