提问



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


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


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

最佳参考


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
}

其它参考2


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


- (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
}

其它参考3


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


我发现samvermette和ribeto的答案非常有用,而且还有最大力量在ribeto的答案中的评论。但这些方法存在问题。在samvermette的回答中暗示的问题就是如果用户希望在其中粘贴一些换行符,键盘会隐藏而不会粘贴任何内容。 ]]


所以我的方法是上面提到的三个解决方案的混合,只检查当字符串的长度为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;
}

其它参考4


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


首先,将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];
}


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

其它参考5


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


夫特:


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()
        }
    }
}

其它参考6


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

yourtextView.delegate=self;


还添加UITextViewDelegate


不要忘记确认协议


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

其它参考7


使用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];
}

其它参考8


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


以下是 Swift 3 语法:


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

其它参考9


就像对samvermette的暗淡评论一样,我也不喜欢检测\\ n的想法。返回键在UITextView中是有原因的,当然是下一行。


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


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


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


脚步:


- 将工具栏添加到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];
}

其它参考10


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



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

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

  • 展开按钮以覆盖整个视图,并确保该按钮位于所有其他对象的后面。简单的方法是将按钮拖动到视图
  • 中列表视图的顶部
  • 控制将按钮拖动到viewController.h文件并创建一个动作(已发送事件:内部触摸),如:


    (IBAction)ExitKeyboard:(id)sender;
    

  • ViewController.m中应该看起来像:


    (IBAction)ExitKeyboard:(id)sender {
        [self.view endEditing:TRUE];
    }
    

  • 运行应用,当您单击TextView时,键盘将消失


其它参考11


在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而不是专门检查返回键,但我认为这没关系。


更新


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

其它参考12


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


在.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;
}

其它参考13


尝试这个 :


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

    return YES;

}

其它参考14


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


步骤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;
}

其它参考15


迅速


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


[75]

其它参考16


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()
            }
        }
    }
}


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

其它参考17


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


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

其它参考18


快速回答:


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

func tap(sender: UITapGestureRecognizer) {
    view.endEditing(true)
}

其它参考19


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


 - (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;

    }

其它参考20


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


将以下操作连接到Interface Builder中的退出时退出事件。
(右键单击TextField并从退出时结束中的cntrl-拖动到以下方法。


-(IBAction)hideTheKeyboard:(id)sender
{
    [self.view endEditing:TRUE];
}

其它参考21


- (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;
}

其它参考22


+ (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;
    }
}

其它参考23


该问题询问如何使用返回键执行此操作,但我认为这可以帮助有意在使用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()。


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


干杯,


穆拉特

其它参考24


-(BOOL)textFieldShouldReturn:(UITextField *)textField; // called from textfield (keyboard)

-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; // good tester function - thanks

其它参考25


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


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


而不是ViewDidLoad我在TextView变为Activity状态时添加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");
}


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

其它参考26


不要忘记设置textView的委托 - 否则resignfirstresponder不会工作。

其它参考27


尝试这个 。


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

其它参考28


对于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()
        }
    }

其它参考29


我的黑客:


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


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


其中_userInput是您的TextField出口