首页 文章

如何使用返回键关闭UITextView的键盘?

提问于
浏览
360

在IB的库中,介绍告诉我们,当按下返回键时, UITextView 的键盘将消失 . 但实际上返回键只能作为'\n' .

我可以添加一个按钮并使用 [txtView resignFirstResponder] 来隐藏键盘 .

但是有没有办法在键盘中添加返回键的操作,这样我就不需要添加 UIButton

30 回答

  • 1

    在viewDidLoad中添加一个观察者

    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(textViewKeyPressed:) name: UITextViewTextDidChangeNotification object: nil];
    

    然后使用选择器检查“\ n”

    -(void) textViewKeyPressed: (NSNotification*) notification {
    
      if ([[[notification object] text] hasSuffix:@"\n"])
      {
        [[notification object] resignFirstResponder];
      }
    }
    

    它确实使用“\ n”而不是专门检查返回键,但我认为这没关系 .

    UPDATE

    请参阅下面的ribto的答案,它使用 [NSCharacterSet newlineCharacterSet] 代替 \n

  • 40

    UITextView 没有任何在用户点击返回键时将被调用的方法 . 如果您希望用户只能添加一行文本,请使用 UITextField . 点击返回并隐藏键盘 UITextView 不遵循界面指南 .

    即便如此,如果要执行此操作,请实现 UITextViewDelegatetextView:shouldChangeTextInRange:replacementText: 方法,并检查替换文本是否为 \n ,隐藏键盘 .

    可能还有其他方法,但我不知道 .

  • 1

    想我会在这里发布片段代替:

    确保声明支持 UITextViewDelegate 协议 .

    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    
        if([text isEqualToString:@"\n"]) {
            [textView resignFirstResponder];
            return NO;
        }
    
        return YES;
    }
    

    Swift 4.0更新:

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if text == "\n" {
            textView.resignFirstResponder()
            return false
        }
        return true
    }
    
  • -1

    我知道这已经回答了,但我真的不喜欢使用新行的字符串文字,所以这就是我所做的 .

    - (BOOL)textView:(UITextView *)txtView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
        if( [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location == NSNotFound ) {
            return YES;
        }
    
        [txtView resignFirstResponder];
        return NO;
    }
    

    Swift 4.0更新:

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if (text as NSString).rangeOfCharacter(from: CharacterSet.newlines).location == NSNotFound {
        return true
    }
    txtView.resignFirstResponder()
    return false
    }
    
  • 5

    刚刚以不同的方式解决了这个问题 .

    • 创建一个将放置在后台的按钮

    • 从属性检查器中,将按钮类型更改为自定义,并使按钮透明 .

    • 展开按钮以覆盖整个视图,并确保该按钮位于所有其他对象的后面 . 简单的方法是将按钮拖动到视图中列表视图的顶部

    • 控制将按钮拖动到 viewController.h 文件并创建一个动作(已发送事件:内部触摸),如:

    (IBAction)ExitKeyboard:(id)sender;
    
    • ViewController.m 中应该如下所示:
    (IBAction)ExitKeyboard:(id)sender {
        [self.view endEditing:TRUE];
    }
    
    • 运行应用程序,当您单击TextView时,键盘将消失
  • 3

    我知道这已经被回答了很多次,但这是我的两分钱 .

    我发现samvermetteribeto的答案非常有用,而maxpowerribeto答案中的评论也是如此 . 但这些方法存在问题 . mattsamvermette _1151511中提到的问题是,如果用户想要在其中粘贴换行符,键盘会隐藏而不会粘贴任何东西 .

    所以我的方法是上面提到的三个解决方案的混合,只检查当字符串的长度为1时输入的字符串是否为新行,因此我们确保用户输入而不是粘贴 .

    这是我做的:

    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
        NSRange resultRange = [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet] options:NSBackwardsSearch];
        if ([text length] == 1 && resultRange.location != NSNotFound) {
            [textView resignFirstResponder];
            return NO;
        }
    
        return YES;
    }
    
  • 31

    更优雅的方法是当用户轻敲键盘框架外的某个位置时关闭键盘 .

    首先,将ViewController的视图设置为UIBuilder中的标识检查器中的“UIControl”类 . 控制 - 将视图拖动到ViewController的头文件中,并将其作为Touch Up Inside事件的动作链接,例如:

    ViewController.h

    -(IBAction)dismissKeyboardOnTap:(id)sender;
    

    在ViewController主文件中,ViewController.m:

    -(IBAction)dismissKeyboardOnTap:(id)sender
        {
             [[self view] endEditing:YES];
        }
    

    您可以使用类似技术进行双击或长按 . 您可能需要将ViewController设置为UITextViewDelegate并将TextView连接到ViewController . 此方法适用于UITextView和UITextField .

    资料来源:Big Nerd Ranch

    编辑:我还想补充说,如果您使用的是UIScrollView,上述技术可能无法通过Interface Builder轻松完成 . 在这种情况下,您可以使用UIGestureRecognizer并在其中调用[[self view] endEditing:YES]方法 . 一个例子是:

    -(void)ViewDidLoad{
        ....
        UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] 
            initWithTarget:self action:@selector(tap:)];
        [self.view addGestureRecognizer: tapRec];
        ....
    }
    
    -(void)tap:(UITapGestureRecognizer *)tapRec{
        [[self view] endEditing: YES];
    }
    

    当用户点击键盘外部并且没有点击入口空间时,键盘将被解除 .

  • 14

    在视图控制器中添加此方法 .

    Swift

    func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
        if text == "\n" {
            textView.resignFirstResponder()
            return false
        }
        return true
    }
    

    这个方法也对你有所帮助:

    /**
    Dismiss keyboard when tapped outside the keyboard or textView
    
    :param: touches the touches
    :param: event   the related event
    */
    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        if let touch = touches.anyObject() as? UITouch {
            if touch.phase == UITouchPhase.Began {
                textField?.resignFirstResponder()
            }
        }
    }
    
  • 7
    -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
        if([text isEqualToString:@"\n"])
            [textView resignFirstResponder];
        return YES;
    }
    
    yourtextView.delegate=self;
    

    另外添加 UITextViewDelegate

    Don't forget to confirm protocol

    如果您没有添加 if([text isEqualToString:@"\n"]) ,则无法编辑

  • 0

    使用uitextview时还有另一种解决方案,你可以在“textViewShouldBeginEditing”中添加工具栏作为InputAccessoryView,从这个工具栏的完成按钮可以解除键盘,其代码如下:

    在viewDidLoad中

    toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)]; //toolbar is uitoolbar object
    toolBar.barStyle = UIBarStyleBlackOpaque;
    UIBarButtonItem *btnDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(btnClickedDone:)];
    [toolBar setItems:[NSArray arrayWithObject:btnDone]];
    

    在textviewdelegate方法中

    - (BOOL)textViewShouldBeginEditing:(UITextView *)textView
    {
         [textView setInputAccessoryView:toolBar];
         return YES;
    }
    

    在工具栏中的Button Done的操作如下:

    -(IBAction)btnClickedDone:(id)sender
    {
        [self.view endEditing:YES];
    }
    
  • 35

    我发现josebama的答案是这个帖子中最完整,最干净的答案 .

    下面是它的 Swift 4 语法:

    func textView(_ textView: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool {
        let resultRange = text.rangeOfCharacter(from: CharacterSet.newlines, options: .backwards)
        if text.count == 1 && resultRange != nil {
            textView.resignFirstResponder()
            // Do any additional stuff here
            return false
        }
        return true
    }
    
  • 333

    就像对samvermette的暗淡评论一样,我也不喜欢检测“\ n”的想法 . 在UITextView中出现“return”键是有原因的,那就是当然要转到下一行 .

    在我看来,最好的解决方案是模仿iPhone消息应用程序 - 即在键盘上添加工具栏(和按钮) .

    我从以下博客文章中获得了代码:

    http://www.iosdevnotes.com/2011/02/iphone-keyboard-toolbar/

    脚步:

    • 将工具栏添加到XIB文件 - 将高度设置为460

    • 添加工具栏按钮项(如果尚未添加) . 如果需要右对齐,还可以向XIB添加灵活的条形按钮项,并移动工具栏按钮项

    • 创建将按钮项链接到的操作resignFirstResponder如下:

    - (IBAction)hideKeyboard:(id)sender {
        [yourUITextView resignFirstResponder];
    }
    

    -然后:

    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
    
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
    
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
    }
    
    - (void)keyboardWillShow:(NSNotification *)notification {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.3];
    
        CGRect frame = self.keyboardToolbar.frame;
        frame.origin.y = self.view.frame.size.height - 260.0;
        self.keyboardToolbar.frame = frame;
    
        [UIView commitAnimations];
    }
    
    - (void)keyboardWillHide:(NSNotification *)notification {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.3];
    
        CGRect frame = self.keyboardToolbar.frame;
        frame.origin.y = self.view.frame.size.height;
        self.keyboardToolbar.frame = frame;
    
        [UIView commitAnimations];
    }
    
  • 4

    使用导航控制器来托管一个条以关闭键盘:

    在.h文件中:

    UIBarButtonItem* dismissKeyboardButton;
    

    在.m文件中:

    - (void)viewDidLoad {
        dismissKeyboardButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissKeyboard)];
    }
    
    -(void)textViewDidBeginEditing:(UITextView *)textView {
        self.navigationItem.rightBarButtonItem = dismissKeyboardButton;
    }
    
    -(void)textFieldDidBeginEditing:(UITextField *)textField {
        self.navigationItem.rightBarButtonItem = dismissKeyboardButton;
    }
    
    -(void)dismissKeyboard {
        [self.textField resignFirstResponder];
        [self.textView resignFirstResponder];
        //or replace this with your regular right button
        self.navigationItem.rightBarButtonItem = nil;
    }
    
  • 471

    试试这个 :

    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
        if ([text isEqualToString:@"\n"]) {
            [self.view endEditing:YES];
        }
    
        return YES;
    
    }
    
  • 4

    //你可以用这个......

    步骤1.第一步是确保声明对 UITextViewDelegate 协议的支持 . 这是在头文件中完成的,例如这里是名为的头

    EditorController.h:

    @interface EditorController : UIViewController  {
      UITextView *messageTextView;
    }
    
    @property (nonatomic, retain) UITextView *messageTextView;
    
    @end
    

    步骤2.接下来,您需要将控制器注册为UITextView的委托 . 继续上面的例子,这里是我如何用 EditorController 初始化 UITextView 作为委托......

    - (id) init {
        if (self = [super init]) {
            // define the area and location for the UITextView
            CGRect tfFrame = CGRectMake(10, 10, 300, 100);
            messageTextView = [[UITextView alloc] initWithFrame:tfFrame];
            // make sure that it is editable
            messageTextView.editable = YES;
    
            // add the controller as the delegate
            messageTextView.delegate = self;
        }
    

    第3步 . 现在,最后一个难题是采取行动以响应 shouldCahngeTextInRange 消息,如下所示:

    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range 
      replacementText:(NSString *)text
    {
        // Any new character added is passed in as the "text" parameter
        if ([text isEqualToString:@"\n"]) {
            // Be sure to test for equality using the "isEqualToString" message
            [textView resignFirstResponder];
    
            // Return FALSE so that the final '\n' character doesn't get added
            return FALSE;
        }
        // For any other character return TRUE so that the text gets added to the view
        return TRUE;
    }
    
  • 0

    迅速

    func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
        if text == "\n" {
            textView.resignFirstResponder()
        }
        return true
    }
    

    and configure

  • 0

    SWIFT代码

    在您的类/ View中实现UITextViewDelegate,如下所示:

    class MyClass: UITextViewDelegate  { ...
    

    将textView委托设置为self

    myTextView.delegate = self
    

    然后实现以下内容:

    func textViewDidChange(_ textView: UITextView) {
        if textView.text.characters.count >= 1 {
    
            if let lastChar = textView.text.characters.last {
    
                if(lastChar == "\n"){
    
                  textView.text = textView.text.substring(to: textView.text.index(before: textView.text.endIndex))
                  textView.resignFirstResponder()
                }
            }
        }
    }
    

    EDIT 我更新了代码,因为将文本字段中的用户输入更改为workarround并且在黑客代码完成后不重置状态永远不是一个好主意 .

  • 0

    您还可以在视图屏幕中触摸时隐藏键盘:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
         UITouch * touch = [touches anyObject];
         if(touch.phase == UITouchPhaseBegan) {
            [txtDetail resignFirstResponder];
          }
     }
    
  • 0

    快速回答:

    override func viewDidLoad() {
        super.viewDidLoad()
        let tapGestureReconizer = UITapGestureRecognizer(target: self, action: "tap:")
        view.addGestureRecognizer(tapGestureReconizer)
    }
    
    func tap(sender: UITapGestureRecognizer) {
        view.endEditing(true)
    }
    
  • 4

    我用这段代码来改变响应者 .

    - (BOOL)textView:(UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text
        {
            if ([text isEqualToString:@"\n"]) {
                //[textView resignFirstResponder];
                //return YES;
                NSInteger nextTag = textView.tag + 1;
                // Try to find next responder
                UIResponder* nextResponder = [self.view viewWithTag:nextTag];
                if (nextResponder) {
                    // Found next responder, so set it.
                    [nextResponder becomeFirstResponder];
                } else {
                    // Not found, so remove keyboard.
                    [textView resignFirstResponder];
                }
                return NO; 
    
    
                return NO;
            }
            return YES;
    
        }
    
  • 3

    好 . 每个人都用技巧给出答案,但我认为实现这一目标的正确方法是

    将以下操作连接到 Interface Builder 中的“ Did End On Exit ”事件 . (右键单击 TextField 并按住' Did end on exit '进行cntrl-拖动到以下方法 .

    -(IBAction)hideTheKeyboard:(id)sender
    {
        [self.view endEditing:TRUE];
    }
    
  • 3
    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range  replacementText:(NSString *)text
    {
        if (range.length==0) {
            if ([text isEqualToString:@"\n"]) {
                [txtView resignFirstResponder];
                if(textView.returnKeyType== UIReturnKeyGo){
    
                    [self PreviewLatter];
                    return NO;
                }
                return NO;
            }
        }   return YES;
    }
    
  • 4
    + (void)addDoneButtonToControl:(id)txtFieldOrTextView
    {
        if([txtFieldOrTextView isKindOfClass:[UITextField class]])
        {
            txtFieldOrTextView = (UITextField *)txtFieldOrTextView;
        }
        else if([txtFieldOrTextView isKindOfClass:[UITextView class]])
        {
            txtFieldOrTextView = (UITextView *)txtFieldOrTextView;
        }
    
        UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0,
                                                                              0,
                                                                              [Global returnDeviceWidth],
                                                                              50)];
        numberToolbar.barStyle = UIBarStyleDefault;
    
    
        UIBarButtonItem *btnDone = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"btn_return"]
                                                                    style:UIBarButtonItemStyleBordered
                                                                   target:txtFieldOrTextView
                                                                   action:@selector(resignFirstResponder)];
    
        numberToolbar.items = [NSArray arrayWithObjects:btnDone,nil];
        [numberToolbar sizeToFit];
    
        if([txtFieldOrTextView isKindOfClass:[UITextField class]])
        {
             ((UITextField *)txtFieldOrTextView).inputAccessoryView = numberToolbar;
        }
        else if([txtFieldOrTextView isKindOfClass:[UITextView class]])
        {
             ((UITextView *)txtFieldOrTextView).inputAccessoryView = numberToolbar;
        }
    }
    
  • 1

    该问题询问如何使用返回键执行此操作,但我认为这可以帮助有意在使用UITextView时使键盘消失的人:

    @IBOutlet weak var textView: UITextView!
    
    private func addToolBarForTextView() {
      let textViewToolbar: UIToolbar = UIToolbar()
      textViewToolbar = UIBarStyle.Default
      textViewToolbar = [
        UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Done, target: self, action: #selector(self.cancelInput)),
        UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil),
        UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: #selector(self.doneInput))
      ]
      textViewToolbar()
      self.textView.inputAccessoryView = textViewToolbar //do it for every relevant textView if there are more than one
    }
    
    func doneInput() {
      self.textView.resignFirstResponder()
    }
    
    func cancelInput() {
      self.textView.text = ""
      self.textView.resignFirstResponder()
    }
    

    在viewDidLoad或其他一些生命周期方法中调用addToolBarForTextView() .

    对我来说,这似乎是完美的解决方案 .

    干杯,

    穆拉特

  • 71
    -(BOOL)textFieldShouldReturn:(UITextField *)textField; // called from textfield (keyboard)
    
    -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; // good tester function - thanks
    
  • 5

    我知道这不是这个问题的确切答案,但我在寻找答案之后找到了这个帖子 . 我认为其他人也有同感 .

    这是我发现UITapGestureRecognizer的变化,我发现它可靠且易于使用 - 只需将TextView的委托设置为ViewController即可 .

    而不是ViewDidLoad我在TextView变为活动状态时添加了UITapGestureRecognizer进行编辑:

    -(void)textViewDidBeginEditing:(UITextView *)textView{
        _tapRec = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    
        [self.view addGestureRecognizer: _tapRec];
        NSLog(@"TextView Did begin");
    }
    

    当我在TextView外部点击时,视图结束编辑模式,UITapGestureRecognizer自行删除,因此我可以继续与视图中的其他控件进行交互 .

    -(void)tap:(UITapGestureRecognizer *)tapRec{
        [[self view] endEditing: YES];
        [self.view removeGestureRecognizer:tapRec];
        NSLog(@"Tap recognized, tapRec getting removed");
    }
    

    我希望这有帮助 . 它似乎很明显,但我从来没有在网络上的任何地方看到过这种解决方案 - 我做错了吗?

  • 5

    不要忘记为textView设置委托 - 否则resignfirstresponder将无效 .

  • 25

    试试这个 .

    NSInteger lengthOfText = [[textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length];
    
  • 5

    对于Xcode 6.4 . ,Swift 1.2 . :

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent)
        {
            super.touchesBegan(touches, withEvent: event)
            if let touch = touches.first as? UITouch
            {
                self.meaningTextview.resignFirstResponder()
            }
        }
    
  • 3

    我这样做了:

    1-创建一个覆盖整个视图的按钮; 2-将其发送到视图的背景,3-更改它在Attribute Inspector中从“Round Rect”键入“Custom”,4-创建动作5-实现动作方法:

    - (IBAction)bgTouched:(id)sender 
    {
        //to dismiss keyboard on bg btn pressed
        [_userInput resignFirstResponder];
    }
    

    其中_userInput是您的TextField出口

相关问题