UITextField 텍스트 변경 이벤트


563

textField에서 텍스트 변경 사항을 어떻게 감지합니까? 대리자 메서드가 shouldChangeCharactersInRange작동하지만 내 요구를 정확하게 충족시키지 못했습니다. YES를 반환 할 때까지 textField 텍스트는 다른 관찰자 메서드에서 사용할 수 없습니다.

예를 들어 내 코드 calculateAndUpdateTextFields에서 업데이트 된 텍스트를 얻지 못하면 사용자가 입력했습니다.

textChangedJava 이벤트 핸들러 와 같은 것을 얻을 수있는 방법 입니다.

- (BOOL)textField:(UITextField *)textField 
            shouldChangeCharactersInRange:(NSRange)range 
            replacementString:(NSString *)string 
{
    if (textField.tag == kTextFieldTagSubtotal 
        || textField.tag == kTextFieldTagSubtotalDecimal
        || textField.tag == kTextFieldTagShipping
        || textField.tag == kTextFieldTagShippingDecimal) 
    {
        [self calculateAndUpdateTextFields];

    }

    return YES;
}

3
이것은 완전히 잘못된 1000 표의 SO 답변의 좋은 예입니다 . iOS는 까다 롭고, 부끄러 우며, 고지로 가득합니다.
Fattie

답변:


1056

에서 적절한 방법 텍스트 변경 콜 다시 UITextField에해야 할 일 :

UITextField 컨트롤에 보낸 문자를 다음과 같이 잡습니다.

// Add a "textFieldDidChange" notification method to the text field control.

Objective-C에서 :

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

스위프트에서 :

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

그런 다음 textFieldDidChange메소드에서 textField의 내용을 검사하고 필요에 따라 테이블 뷰를 다시로드 할 수 있습니다.

그것을 사용하고 calculateAndUpdateTextFields를 으로 넣을 수 있습니다 selector.


18
이것은 더 나은 솔루션입니다. Nibs 또는 Storyboards에서 이것을 설정할 수 있고 과도한 UITextFieldTextDidChangeNotification 코드를 작성할 필요가 없습니다
PostCodeism

3
유일한 문제는. (의 UITextField *)에 textField shouldChangeCharactersInRange : (NSRange) 범위 replacementString (는 NSString *) 문자열 (BOOL)에 textField - 그것은과 함께 나를 위해 작동하지 않습니다
iWheelBuy

4
@iWheelBuy 이 메소드에서 NO리턴 할 때 NO기본적으로 필드의 텍스트가 변경되지 않아야 하므로 논리적 인을 리턴 할 때만 리턴 됩니다.
gitaarik

2
이로 인해 변경이 발생한 편집에 좋습니다. 다음을 통해 발생하는 프로그래밍 방식 변경 사항은 포착하지 않습니다 textField.text = "Some new value";. 이것을 잡는 영리한 방법이 있습니까?
Benjohn

10
당신은 애플과 함께 UITextFieldDelegate무언가 func textField: UITextField, didChangeText text: String가 포함되었을 것이라고 생각했을 것입니다.하지만 ... (애플의 사람들에게 더러운 표정을
Brandon

394

XenElement의 답변이 제자리에 있습니다.

UITextField를 마우스 오른쪽 버튼으로 클릭하고 "Editing Changed"send 이벤트를 서브 클래스 유닛으로 드래그하여 인터페이스 빌더에서도 위와 같은 작업을 수행 할 수 있습니다.

UITextField 변경 이벤트


2
쉽지는 않지만 10-15 분 동안 검색 한 후에 우연히 답변에 걸림돌이 될 때까지 이러한 가능성을 발견하지 못했습니다. 나에게서 또 다른 +1을 가져라. 코드 기반 솔루션과 IB 기반 솔루션 모두 이와 같은 질문에 대해 높은 투표를 한 것이 좋습니다.
Mark Amery

방금 6.3에서 확인했는데 거기 있습니다. 이것은 UITextView이며 마우스 오른쪽 버튼으로 클릭하고 "변경된 편집"을 참조하십시오.
William T.

4
왜 지구상에서 이름이 Editing Changed입니까? 미친! 솔루션에 감사드립니다 :-)
malhal

3
변경 사항을 편집 할 때 이벤트가 호출되는 반면 텍스트 필드가 편집을 마치면 첫 번째 응답자를 사임 할 때 변경되는 값이 발생합니다. UITextFieldTextDidChangeNotification은 UITextField 알림이며 UIControlEventValueChanged는 UIButton 하위 클래스 인 UIControl에 의해 구현됩니다.
Camsoft

2
나는이 텍스트 필드에서 사용자 탭과 같은 일을하지 않는주의 및 자동 고침 텍스트 콘텐츠 대체
noobular

136

이벤트 리스너를 설정하려면 다음을 수행하십시오.

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

실제로 들으려면 :

- (void)textFieldDidChange:(UITextField *)textField {
    NSLog(@"text changed: %@", textField.text);
}

멋있는. 이미 TextFieldDelegate 인 ViewController 기본 클래스에서 textField-change-listening을 구현하고 싶기 때문에이 방법이 마음에 듭니다. 이렇게하면 매력처럼 (하위 뷰의 textField)에 대해 Target : baseControllerMethod를 추가 할 수 있습니다. 고마워!
HBublitz

87

빠른:

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

그런 다음 콜백 함수를 구현하십시오.

@objc func textFieldDidChange(textField: UITextField){

print("Text changed")

}

2
나를 위해 일한 나는 이미 이것을 시도했지만 함수가 textField 인수가 필요하다는 것을 깨닫지 못했습니다. 이 방법으로 문제가 해결되지 않으면 선택기에 textField를 전달할 인수가 있는지 확인하십시오 (사용하지 않더라도).
werm098

textFieldDidChange에서 textField 앞에 _를 다음과 같이 추가하십시오. func textFieldDidChange (textField : UITextField) {...}
Makalele

30

여기에 언급 된 바와 같이 : UITextField 텍스트 변경 이벤트 , iOS 6 (iOS 6.0 및 6.1 확인)에서는 UITextField을 관찰하는 것만으로 는 객체의 변경 사항을 완전히 감지 할 수없는 것으로 보입니다 UITextFieldTextDidChangeNotification.

내장 iOS 키보드로 직접 변경 한 내용 만 추적되는 것 같습니다. 즉 , UITextField다음과 같이 호출 하여 객체 를 변경하면 변경 myUITextField.text = @"any_text"사항에 대한 알림이 전혀 표시되지 않습니다.

이것이 버그인지 또는 의도 된 것인지 모르겠습니다. 문서에서 합리적인 설명을 찾지 못했기 때문에 버그처럼 보입니다. UITextField text change event 에도 설명 되어 있습니다 .

이것에 대한 나의 "솔루션"은 실제로 내 모든 변경 사항에 대한 알림을 실제로 게시하는 것입니다 UITextField(내장 iOS 키보드를 사용하지 않고 변경이 완료된 경우). 이 같은:

myUITextField.text = @"I'm_updating_my_UITextField_directly_in_code";

NSNotification *myTextFieldUpdateNotification  = 
  [NSNotification notificationWithName:UITextFieldTextDidChangeNotification
                  object:myUITextField];

[NSNotificationCenter.defaultCenter 
  postNotification:myTextFieldUpdateNotification];

이런 식 으로 코드에서 "수동으로"업데이트하거나 내장 iOS 키보드를 통해 객체 의 .text속성 을 변경할 때 동일한 알림을 받는다는 것을 100 % 확신합니다 UITextField.

문서화 된 동작이 아니기 때문에이 방법을 사용하면 UITextField객체 의 동일한 변경에 대해 2 개의 알림이 수신 될 수 있습니다 . 필요에 따라 ( UITextField.text변경할 때 실제로 수행하는 작업 ) 이는 불편할 수 있습니다.

알림이 UITextFieldTextDidChangeNotification자신의 알림인지 "iOS-made"인지 실제로 알아야하는 경우 약간 다른 방법으로 사용자 지정 알림 (이 아닌 사용자 지정 이름으로)을 게시하는 것입니다.

편집하다:

방금 더 나은 것으로 생각되는 다른 접근법을 찾았습니다.

여기에는 Objective-C의 KVO (Key-Value Observing) 기능 ( http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid / 10000177-BCICJDHA ).

기본적으로 귀하는 자신을 속성의 관찰자로 등록하고이 속성이 변경되면 이에 대한 알림을받습니다. "원칙"은 NSNotificationCenter작동 방식 과 매우 유사하며 ,이 접근 방식은 iOS 6에서 자동으로 작동한다는 주요 이점입니다 (수동으로 알림을 게시하는 것과 같은 특별한 조정없이).

우리에 대한 UITextField당신의 당신이 예를 들어,이 코드를 추가 할 경우이 잘 작동 -scenario, UIViewController텍스트 필드를 포함 :

static void *myContext = &myContext;

- (void)viewDidLoad {
  [super viewDidLoad];

  //Observing changes to myUITextField.text:
  [myUITextField addObserver:self forKeyPath:@"text"
    options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld 
    context:myContext];

}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary *)change context:(void *)context {

  if(context == myContext) {
    //Here you get notified every time myUITextField's "text" property is updated
    NSLog(@"New value: %@ - Old value: %@",
      [change objectForKey:NSKeyValueChangeNewKey],
      [change objectForKey:NSKeyValueChangeOldKey]);
  }
  else 
    [super observeValueForKeyPath:keyPath ofObject:object 
      change:change context:context];

}

"컨텍스트"관리와 관련된이 답변의 출처 : https://stackoverflow.com/a/12097161/2078512

참고 : 내장 iOS 키보드 편집하는 UITextField동안 텍스트 필드의 "text"속성이 입력 / 제거 될 때마다 업데이트되지 않는 것 같습니다. 대신 텍스트 필드의 첫 번째 응답자 상태를 사임 한 후 텍스트 필드 개체가 "전체로"업데이트됩니다.


5
XenElement의 답변에서 target-action 메소드를 사용하십시오. 수십 줄의 코드가 필요한 경우 간단하게 "필요한"작업을 수행하면 잘못했을 수 있습니다.
jrturton

6
그것은 의도 된 행동으로 보입니다. 코드에서 시작된 이벤트에 대해 다른 대리자 메서드 (예 : 스크롤, 선택)가 호출되지 않습니다.
jrturton

1
참고 UIKit는 KVO를 준수하도록 보장되지 KVO 솔루션은하지 않습니다 반드시 작업 때문에.
Pang

@jrturton,“왜”질문과 관련하여 다른 클래스 (어쩌면 장식, 애니메이션 등)에서 텍스트 필드에서 일어나는 일에 응답 해야하는 것은 일반적입니다.
Fattie

27

StoryboardCTRL 에서 @IBAction다음과 같이 이벤트를 쉽게 변경하고 구성 할 수 있습니다 .

여기에 이미지 설명을 입력하십시오


14

빠른 버전으로 여기에 동일합니다.

textField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)

func textFieldDidChange(textField: UITextField) {

}

감사


12

shouldChangeChractersInRange의 동작을 변경하는 문제를 해결했습니다. NO를 반환하면 iOS에서 변경 사항을 내부적으로 적용하지 않고 대신 수동으로 변경하고 변경 후 작업을 수행 할 수 있습니다.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //Replace the string manually in the textbox
    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
    //perform any logic here now that you are sure the textbox text has changed
    [self didChangeTextInTextField:textField];
    return NO; //this make iOS not to perform any action
}

3
이 솔루션의 문제점은 다음과 같습니다. 커서 위치가 필드의 끝으로 설정됩니다 (textField.text = ...를 수행하자마자). 따라서 사용자가 필드 중간에있는 문자를 편집하려면 각 키를 누를 때마다 커서가 필드의 끝으로 이동합니다. 사용해보십시오.
FranticRock

좋은 점 @ 알렉스,하지만 해결하기 간단합니다. 로컬 NSString에서 결과 값을 계산하고 didChangeTextInTextField : toText : 메서드에 전달한 다음 YES를 반환하여 iOS가 업데이트를 수행하도록합니다.
jk7

11

스위프트 버전 테스트 :

//Somewhere in your UIViewController, like viewDidLoad(){ ... }
self.textField.addTarget(
        self, 
        action: #selector(SearchViewController.textFieldDidChange(_:)),
        forControlEvents: UIControlEvents.EditingChanged
)

설명 된 매개 변수 :

self.textField //-> A UITextField defined somewhere in your UIViewController
self //-> UIViewController
.textFieldDidChange(_:) //-> Can be named anyway you like, as long as it is defined in your UIViewController

그런 다음 위에서 만든 방법을 다음에 추가하십시오 UIViewController.

//Gets called everytime the text changes in the textfield.
func textFieldDidChange(textField: UITextField){

    print("Text changed: " + textField.text!)

}

7

스위프트 4

func addNotificationObservers() {

    NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChangeAction(_:)), name: .UITextFieldTextDidChange, object: nil)

}

@objc func textFieldDidChangeAction(_ notification: NSNotification) {

    let textField = notification.object as! UITextField
    print(textField.text!)

}

5

스위프트 3.0 :

let textField = UITextField()

textField.addTarget(
    nil,
    action: #selector(MyClass.textChanged(_:)),
    for: UIControlEvents.editingChanged
)

다음과 같은 클래스를 사용하십시오.

class MyClass {
    func textChanged(sender: Any!) {

    }
}

4

스위프트 3 버전

yourTextField.addTarget(self, action: #selector(YourControllerName.textChanges(_:)), for: UIControlEvents.editingChanged)

그리고 여기에서 변화를 얻으십시오

func textChanges(_ textField: UITextField) {
    let text = textField.text! // your desired text here
    // Now do whatever you want.
}

도움이 되길 바랍니다.


2

다른 방법은 실제로 중국어 입력 방법을 사용할 때 실제로 입력되지 않은 입력 상자를 수신하기 때문에이 문제를 해결하려면 알림을 사용해야합니다. viewDidload에서

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
                                                 name:@"UITextFieldTextDidChangeNotification"
                                               object:youTarget];

그때

- (void)textFiledEditChanged:(NSNotification *)obj {
UITextField *textField = (UITextField *)obj.object;
NSString *toBestring = textField.text;
NSArray *currentar = [UITextInputMode activeInputModes];
UITextInputMode *currentMode = [currentar firstObject];
if ([currentMode.primaryLanguage isEqualToString:@"zh-Hans"]) {
    UITextRange *selectedRange = [textField markedTextRange];
    UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
    if (!position) {
        if (toBestring.length > kMaxLength)
            textField.text =  toBestring;
} 

}

마지막으로, 당신은 실행됩니다.


2

스위프트 3.1 :

선택기 : ClassName.MethodName

  cell.lblItem.addTarget(self, action: #selector(NewListScreen.fieldChanged(textfieldChange:)), for: .editingChanged)

  func fieldChanged(textfieldChange: UITextField){

    }

2

스위프트 3 버전 :

class SomeClass: UIViewController, UITextFieldDelegate { 

   @IBOutlet weak var aTextField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        aTextField.delegate = self
        aTextField.addTarget(self, action: #selector(SignUpVC.textFieldDidChange), for: UIControlEvents.editingChanged)        
    }

   func textFieldDidChange(_ textField: UITextField) {

       //TEXT FIELD CHANGED..SECRET STUFF

   }

}

델리게이트를 설정하는 것을 잊지 마십시오.


뷰 컨트롤러에 6 개의 텍스트 필드가 있는데 마지막 텍스트 필드가 변경되었는지 확인하고 싶습니다 ( "마지막 텍스트 필드가 변경되었습니다!")?
Saeed Rahmatolahi

먼저 textField에 Iboutlet을 만드십시오. 그런 다음 답변에 표시된 것처럼 대리자와 addTarget을 설정하십시오. textFieldDidChange 대리자 함수에 다음을 추가하십시오. "if textField == yourLastTextField {print ("마지막 텍스트 필드가 변경되었습니다! ")} 지금은 컴퓨터에 액세스 할 수 없습니다. 내 컴퓨터에가요
조셉 프랜시스

2

폐쇄와 함께 :

   class TextFieldWithClosure: UITextField {
    var targetAction: (() -> Void)? {
        didSet {
            self.addTarget(self, action: #selector(self.targetSelector), for: .editingChanged)
        }
    }

    func targetSelector() {
        self.targetAction?()
    }
    }

그리고 사용

textField.targetAction? = {
 // will fire on text changed
 }

2
  1. KVO 솔루션 이 작동하지 않습니다

KVO가 컨트롤 아이폰 OS에서 작동하지 않습니다 http://stackoverflow.com/a/6352525/1402846 https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/KVO.html

  1. 관찰 수업에서 다음을 수행하십시오.

보고자하는 텍스트보기를 알고 있다면 :

var watchedTextView: UITextView!

이 작업을 수행:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(changed),
    name: UITextView.textDidChangeNotification,
    object: watchedTextView)

그러나 다음 사항에주의하십시오.

  • 한 번만 호출하고 싶을 수 있으므로 예를 들어 호출하지 마십시오.layoutSubviews

  • 준비 과정에서 언제 가장 잘 전화해야하는지 알기가 매우 어렵습니다. 상황에 따라 다릅니다. 불행히도 표준 고정 솔루션은 없습니다

  • 예를 들어, 당신은 일반적으로 확실하게 할 수 없습니다 에서 호출 init물론 이후, 시간이 watchedTextView아직 존재하지 않을 수 있습니다

.

  1. 다음 문제는 ...

프로그래밍 방식으로 텍스트를 변경할 때 알림이 호출 되지 않습니다 .

이것은 iOS 엔지니어링에서 오래되고 어리 석고 성가신 것입니다.

.text 속성이 프로그래밍 방식으로 변경 될 때 컨트롤은 단순히 이야기를 끝내지 않습니다 .

물론 모든 앱은 사용자가 게시 한 후 필드를 지우는 것과 같이 프로그래밍 방식으로 텍스트를 설정하므로 이는 매우 성가신 일입니다.

다음과 같이 텍스트 뷰 (또는 유사한 컨트롤)를 서브 클래 싱해야합니다.

class NonIdioticTextView: UIITextView {

    override var text: String! {
        // boilerplate code needed to make watchers work properly:
        get {
            return super.text
        }
        set {
            super.text = newValue
            NotificationCenter.default.post(
                name: UITextView.textDidChangeNotification,
                object: self)
        }

    }

}

(팁 - 슈퍼 전화를 잊지 않는 것은 와야 전에 ! 포스트 전화를.)

아니오 , 당신은 단지 위와 같이 서브 클래스에 의한 제어를 해결하지 않는 한, 솔루션을 사용할 수 있습니다. 이것이 유일한 해결책입니다.

알림

UITextView.textDidChangeNotification

결과

func textViewDidChangeSelection(_ textView: UITextView) 

호출되고 있습니다.

( 아닙니다 textViewDidChange .)


1
[[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(didChangeTextViewText:) 
name:UITextFieldTextDidChangeNotification object:nil];



- (void) didChangeTextViewText {
 //do something
}

0

한 가지는 UITextField가 여러 개있을 수 있다는 것입니다. 따라서 태그를 제공하면 태그를 켤 수 있습니다. 모든 클래스에서 옵저버를 설정하는 방법은 다음과 같습니다.

private func setupTextFieldNotification() {
    NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: nil, queue: OperationQueue.main) { (notification) in
        if let textField = notification.object as? UITextField, textField.tag == 100, let text = textField.text {
            print(#line, text)
        }
    }
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

-1

스위프트 4 버전

키-값 관찰 사용 다른 객체의 속성 변경에 대해 객체에 알립니다.

var textFieldObserver: NSKeyValueObservation?

textFieldObserver = yourTextField.observe(\.text, options: [.new, .old]) { [weak self] (object, changeValue) in
  guard let strongSelf = self else { return }
  print(changeValue)
}

좋은 생각. 이것을 문맥에 싸서 알려주십시오.
Revanth Kausikan 19

1
불행히도 이것은 완전히 잘못된 것입니다. KVO는 iOS 용 컨트롤에서 작동하지 않습니다 : stackoverflow.com/a/6352525/1402846 developer.apple.com/library/archive/documentation/General/…
Fattie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.