如何解散键盘的UITextView与返回键?

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

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

但是是否有一种方法可以为键盘中的返回键添加动作,这样我就不需要添加UIButton了?

321792 次浏览

UITextView没有任何在用户点击返回键时被调用的方法。如果你想让用户只能添加一行文本,使用UITextField。按回车键并隐藏UITextView的键盘不符合接口准则。

即使这样,如果你想这样做,实现UITextViewDelegatetextView:shouldChangeTextInRange:replacementText:方法,并在检查替换文本是否为\n时,隐藏键盘。

也许还有别的办法,但我不知道有什么办法。

我想我应该把这个片段放在这里:

确保声明了对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
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField; // called from textfield (keyboard)


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

我知道这已经回答了,但我真的不喜欢使用字符串字面量的换行,所以这是我所做的。

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

使用导航控制器托管一个栏来解除键盘:

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

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

将以下动作连接到Interface Builder中的"退出时是否结束"事件。 (右键单击TextField和cntrl-drag从'在退出时结束'到下面的方法

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

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

在我看来,最好的解决方案是模仿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];
}
-(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"]),你不能编辑

在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

一种更优雅的方法是,当用户点击键盘框架之外的某个地方时,取消键盘。

首先,在UIBuilder的标识检查器中将你的ViewController的视图设置为类“UIControl”。control -拖动视图到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,上述技术可能不容易通过接口构建器工作。在这种情况下,你可以使用一个UIGestureRecognizer并调用其中的[[self view] enditing:YES]方法。一个例子是:

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


-(void)tap:(UITapGestureRecognizer *)tapRec{
[[self view] endEditing: YES];
}

当用户在键盘外点击,并且没有点击输入空间时,键盘将关闭。

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

这是我的UITapGestureRecognizer的方差,我发现可靠和易于使用-只需设置TextView的委托到ViewController。

而不是ViewDidLoad我添加了UITapGestureRecognizer当TextView成为编辑活动:

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

我希望这能有所帮助。这似乎是显而易见的,但我从来没有在网上看到过这个解决方案-我做错了什么吗?

我的诀窍是:

1-创建一个按钮覆盖整个视图; 2-将它发送到视图的后台, 3-在属性检查器中将它的类型从“圆角矩形”改为“自定义” 4-创建一个动作 5-执行action方法:

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

哪里_userInput是你的TextField出口

试试这个:

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


return YES;


}

你也可以隐藏键盘时,触摸在视图屏幕:

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

用另一种方法解决了这个问题。

  • 创建一个将放置在背景中的按钮
  • 从属性检查器中,将按钮类型更改为自定义,并使按钮透明。
  • 展开按钮以覆盖整个视图,并确保按钮位于所有其他对象的后面。要做到这一点,简单的方法是将按钮拖到视图中的列表视图顶部
  • Control拖动按钮到viewController.h文件并创建一个动作(Sent Event: Touch Up Inside),如:

    (IBAction)ExitKeyboard:(id)sender;
    
  • In ViewController.m should look like :

    (IBAction)ExitKeyboard:(id)sender {
    [self.view endEditing:TRUE];
    }
    
  • Run app, and when you click away from the TextView, the keyboard disappears

不要忘记为textView设置委托-否则resignfirstresponder将无法工作。

我知道这个问题已经被回答过很多次了,但下面是我对这个问题的看法。

我发现samvermetteribeto的答案非常有用,还有maxpowerribeto的答案中的注释。但这些方法存在一个问题。马特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;
}
- (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;
}
有另一个解决方案,而使用uitextview, 你可以添加工具栏作为InputAccessoryView在“textViewShouldBeginEditing”,从这个工具栏的完成按钮,你可以解除键盘,这是如下代码:

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

在操作按钮完成,这是在工具栏如下:

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

函数hideQueboard。

- (void)HideQueyboard
{
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder)   to:nil from:nil forEvent:nil];
}

银行的国际代码

在你的类/视图中实现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()
}
}
}
}

<强>编辑 我更新了代码,因为它从来不是一个好主意,改变用户在文本框的输入,以解决问题,而不是在黑客代码完成后重新设置状态

//你可以使用这个…

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

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

斯威夫特:

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

试试这个。

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

迅速回答:

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


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

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

我使用这段代码来更改响应器。

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


}

斯威夫特

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

and configure .

问题问的是如何用返回键来做,但我认为这可以帮助那些想要在使用UITextView时让键盘消失的人:

private func addToolBarForTextView() {
let textViewToolbar: UIToolbar = UIToolbar()
textViewToolbar.barStyle = .default
textViewToolbar.items = [
UIBarButtonItem(title: "Cancel", style: .done,
target: self, action: #selector(cancelInput)),
UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
target: self, action: nil),
UIBarButtonItem(title: "Post Reply", style: .done,
target: self, action: #selector(doneInput))
]
textViewToolbar.sizeToFit()
yourTextView.inputAccessoryView = textViewToolbar
}


@objc func cancelInput() { print("cancel") }
@objc func doneInput() { print("done") }


override func viewDidLoad() {
super.viewDidLoad()
addToolBarForTextView()
}

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

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

欢呼,

Murat

对于Swift 3,这段代码允许我在UITextView之外按下键来解除键盘。

@IBOutlet weak var comment: UITextView!


override func viewDidLoad() {
super.viewDidLoad()


comment.delegate = self


let tapGestureRecogniser = UITapGestureRecognizer(target: self, action: #selector(tap))
view.addGestureRecognizer(tapGestureRecogniser)
}


func tap(sender: UITapGestureRecognizer) {
if comment.isFirstResponder {
comment.resignFirstResponder()
}
}

我发现josebama的答案是这个线程中最完整和干净的答案。

下面是它的斯威夫特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
}

你应该将UIToolbar添加到顶部UITextView,而不是使用shouldChangeTextIn

在Swift 4中

let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
toolbar.barStyle = .default
toolbar.items = [
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(doneAction))
]
textView.inputAccessoryView = toolbar
@objc func doneAction(){
self.textView.resignFirstResponder()
}

类似于使用UITextViewDelegate的其他答案,但一个更新的swift接口isNewline将是:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if let character = text.first, character.isNewline {
textView.resignFirstResponder()
return false
}
return true
}