我有一个 buttonA,当单击 buttonA 时,我希望键盘在 inputAccessoryView 中显示一个 UITextField。有没有办法手动显示键盘并设置 inputAccessoryView 而最初没有 UITextField ?
谢谢。
我有一个 buttonA,当单击 buttonA 时,我希望键盘在 inputAccessoryView 中显示一个 UITextField。有没有办法手动显示键盘并设置 inputAccessoryView 而最初没有 UITextField ?
谢谢。
如果没有可以成为第一响应者的对象,您将无法召唤键盘。有两种解决方法:
子类 aUIView
并在其中实现UIKeyInput
协议。例如:
在您的 .h 文件中:
@interface InputObject : UIView<UIKeyInput>
@property (nonatomic, copy) NSString *text;
@property (nonatomic, strong) UIView *inputAccessoryView; // You must override inputAccessoryView , since it's readonly by default
@end
在您的 .m 文件中,实现协议:
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (BOOL)hasText
{
return [self.text length];
}
- (void)insertText:(NSString *)text
{
NSString *selfText = self.text ? self.text : @"";
self.text = [selfText stringByAppendingString:text];
[[NSNotificationCenter defaultCenter] postNotificationName:kInputObjectTextDidChangeNotification object:self];
}
- (void)deleteBackward
{
if ([self.text length] > 0)
self.text = [self.text substringToIndex:([self.text length] - 1)];
else
self.text = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:kInputObjectTextDidChangeNotification object:self];
}
假设您想在 中召唤键盘-viewDidAppear:
,代码如下:
- (void)viewDidLoad
{
[super viewDidLoad];
// inputObject and textField are both your ivars in your view controller
inputObject = [[InputObject alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
inputObject.inputAccessoryView = textField;
[self.view addSubview:inputObject];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(inputObjectTextDidChange:) name:kInputObjectTextDidChangeNotification object:nil];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[inputObject becomeFirstResponder]; // This will summon the keyboard
}
然后在视图控制器中实现通知选择器:
- (void)inputObjectTextDidChange:(NSNotification *)notification
{
// Just set the text here. notification.object is actually your inputObject.
textField.text = ((InputObject *)(notification.object)).text;
}
这可能就是您所说的“在最初没有 UITextField 的情况下设置 inputAccessoryView”的意思
inputAccessoryView
通过仔细安排其动画让 textField “假装”为。但是此解决方案需要您的 textField 成为第一响应者。 首先,你观察你的键盘事件-viewDidLoad
:
- (void)viewDidLoad
{
[super viewDidLoad];
// Init the textField and add it as a subview of self.view
textField = [[UITextField alloc] init];
textField.backgroundColor = [UIColor redColor];
[self.view addSubview:textField];
// Register keyboard events
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil];
}
其次,设置你的框架,textField
以-viewWillAppear:
保证它的框架不会受到自动调整大小的影响:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
textField.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds), CGRectGetWidth(self.view.bounds), 50);
}
然后,安排你的textField
动画,让它与键盘动画同步。您的键盘通知选择器可能是这样的:
- (void)keyboardWillShowNotification:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
UIViewAnimationCurve curve = [[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
CGFloat duration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
CGRect keyboardFrame = [[userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrame = [self.view convertRect:keyboardFrame toView:self.view];
[UIView animateWithDuration:duration delay:0.0f options:(UIViewAnimationOptions)curve animations:^{
CGRect textFieldFrame = textField.frame;
textFieldFrame.origin.y = keyboardFrame.origin.y - CGRectGetHeight(textFieldFrame);
textField.frame = textFieldFrame;
}completion:nil];
}
- (void)keyboardWillHideNotification:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
UIViewAnimationCurve curve = [[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
CGFloat duration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
[UIView animateWithDuration:duration delay:0.0f options:(UIViewAnimationOptions)curve animations:^{
textField.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds), CGRectGetWidth(self.view.bounds), 50);
}completion:nil];
}
最后,调用[textField becomeFirstResponder]
触发动画。
另一种解决方案是将这些方法添加到您的UIViewController
实现中:
- (void)viewDidLoad {
[super viewDidLoad];
[self reloadInputViews];
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (UIView *)inputAccessoryView {
if (!_textField) {
_textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
_textField.backgroundColor = [UIColor whiteColor];
_textField.delegate = self;
}
return _textField;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
并将_textField
变量添加到您的界面:
@interface ViewController : UIViewController <UITextFieldDelegate> {
UITextField *_textField;
}
@end
这个问题的一个hacky解决方案是在视图中有一个 UITextField 但被隐藏,然后在它上面调用 [textfield becomeFirstResponder] 。
我刚刚测试了它,这有效
UITextField * randofield = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[self.view addSubview:randofield];
// doesn't have to be hidden... but to be safe.
randofield.hidden = YES;
[randofield becomeFirstResponder];
你必须让它成为视图的子视图,否则这将不起作用。
使用基于刘耀东答案的自动布局约束的 Swift 版本。
要求您在屏幕底部和文本视图之间设置垂直空间约束。请注意,设置偏移量必须发生在动画上下文之外,并且只有布局发生在动画上下文内。
@IBOutlet weak var textViewBottomOffsetConstraint: NSLayoutConstraint!
override public func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillHide(notification: NSNotification) {
guard let userInfo = notification.userInfo else {
return
}
animateTextFieldOffset(0, userInfo: userInfo)
}
func keyboardWillShow(notification: NSNotification) {
guard let userInfo = notification.userInfo, var keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() else {
return
}
keyboardFrame = view.convertRect(keyboardFrame, toView: view)
animateTextFieldOffset(keyboardFrame.size.height, userInfo: userInfo)
}
func animateTextFieldOffset(offset: CGFloat, userInfo: [NSObject: AnyObject] ){
guard let animationCurveInt = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int, let animationCurve = UIViewAnimationCurve(rawValue:animationCurveInt) else { return }
guard let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double else { return }
self.loginViewBottomOffsetConstraint.constant = offset
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(animationDuration)
UIView.setAnimationCurve(animationCurve)
UIView.setAnimationBeginsFromCurrentState(true)
self.view.layoutIfNeeded()
UIView.commitAnimations()
}