使用iOS SDK:
我有一个带UITextFields的UIView,可以启动键盘。我需要它能够:
启动键盘后,允许滚动UIScrollView的内容以查看其他文本字段自动“跳转”(通过向上滚动)或缩短
我知道我需要一个UIScrollView。我已经尝试将UIView的类更改为UIScrollView,但仍然无法上下滚动文本框。
我需要UIView和UIScrollView吗?一个在另一个里面吗?
要自动滚动到活动文本字段,需要执行哪些操作?
理想情况下,尽可能多的组件设置将在Interface Builder中完成。我只想编写需要的代码。
注意:我使用的UIView(或UIScrollView)是由一个选项卡(UITabBar)启动的,它需要正常工作。
我正在添加滚动条,只为键盘出现时使用。尽管不需要它,但我觉得它提供了一个更好的界面,例如,用户可以滚动和更改文本框。
当键盘上下移动时,我可以改变UIScrollView的框架大小。我只是在使用:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50); // Resize
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
// Keyboard will hide
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height + 215 - 50); // Resize
}
然而,这不会自动“向上移动”或将可见区域中的下部文本字段居中,这是我真正想要的。
我在这里没有看到这种可能性,所以我添加了它,因为我尝试了答案中的方法,但几个小时后发现在iOS6/7中的XCode 5中有一种更简单的方法:使用NSLayoutConstraints。
请参见:自动布局约束-键盘
这是我的代码:
.m文件:
// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
NSLog(@"keyboardWillBeShown:");
[self.PhoneNumberLabelOutlet setHidden:TRUE];
CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
thisConstraint.constant -= heightOfLabel;
}
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGFloat oldConstant = [self.SignInYConstraint constant];
self.SignInYConstraint.constant = oldConstant + kbSize.height;
[self.view setNeedsUpdateConstraints];
NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
[self.view layoutIfNeeded];
}];
}
.h文件:
#import <UIKit/UIKit.h>
@interface SignInViewController : UIViewController {
UITextField* _activeField;
}
- (void)signInCallback:(NSObject*)object;
@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;
@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UIButton *SignInButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;
@end
如果文本字段未完全或部分隐藏,则我们不应更改任何内容。我们应该计算隐藏的精确相交区域(键盘的框架和文本字段的框架),然后我们应该更改视图的框架。这里我给出了一个完整的例子。声明3个变量
#定义衬垫10@接口PKViewController()@属性(非原子,赋值)CGRect-originalViewFrame//原始视图的框架@属性(非原子,强)UITextField*activeTextField;//当前文本字段@属性(非原子,赋值)CGRect keyBoardRect;//安全板覆盖面积@完
存储原始帧
- (void)viewDidLoad {
[super viewDidLoad];
_originalViewFrame = self.view.frame;
}
将视图控制器添加为键盘通知的观察者
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
移除观察者
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
当键盘出现时存储键盘覆盖的区域,当键盘消失时将其设置为CGRectZero
- (void)keyboardWasShown:(NSNotification *)notification{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
_keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);
[self moveTextFieldUP];
}
- (void) keyboardWillHide:(NSNotification *)notification{
_keyBoardRect = CGRectZero;
[self setDefaultFrame];
}
存储活动文本字段
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
_activeTextField = textField;
//When keyboard is already present but the textfield is hidden. Case:When return key of keyboard makes the next textfield as first responder
if (!CGRectIsEmpty(_keyBoardRect)) {
[self moveTextFieldUP];
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
现在我们应该改变视图的框架
- (void)moveTextFieldUP{
CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.origin.y, _activeTextField.frame.size.width, _activeTextField.frame.origin.y+_activeTextField.frame.size.height);
if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {
CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);
CGFloat newY = _originalViewFrame.origin.y - intersectRect.size.height;
CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;
CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);
[UIView animateWithDuration:0.3 animations:^{
[self.view setFrame:newFrame];
}];
NSLog(@"Intersect");
}
}
- (void)setDefaultFrame {
[UIView animateWithDuration:0.3 animations:^{
[self.view setFrame:_originalViewFrame];
}];
}
对于Swift Developer,使用Swift 3,这里是回购https://github.com/jamesrochabrun/KeyboardWillShow
import UIKit
class ViewController: UIViewController {
//1 Create a view that will hold your TEXTFIELD
let textField: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.layer.borderColor = UIColor.darkGray.cgColor
tf.layer.borderWidth = 3.0
return tf
}()
//2 global variable that will hold the bottom constraint on changes
var textfieldBottomAnchor: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
//3 add the view to your controller
view.addSubview(textField)
textField.heightAnchor.constraint(equalToConstant: 80).isActive = true
textField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
textField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
textfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)
textfieldBottomAnchor?.isActive = true
setUpKeyBoardObservers()
}
//4 Use NSnotificationCenter to monitor the keyboard updates
func setUpKeyBoardObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
//5 toggle the bottom layout global variable based on the keyboard's height
func handleKeyboardWillShow(notification: NSNotification) {
let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect
if let keyboardFrame = keyboardFrame {
textfieldBottomAnchor?.constant = -keyboardFrame.height
}
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
if let keyboardDuration = keyboardDuration {
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
})
}
}
func handleKeyboardWillHide(notification: NSNotification) {
textfieldBottomAnchor?.constant = 0
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
if let keyboardDuration = keyboardDuration {
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
})
}
}
//6 remove the observers
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
}