使用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
我迟到了一点。您应该在viewController上添加scrollView。
您必须实现以下2种方法。
TextField委托方法。
- (void)textFieldDidBeginEditing:(UIView *)textField {
[self scrollViewForTextField:reEnterPINTextField];
}
然后在委托方法中调用以下方法。
- (void)scrollViewForTextField:(UIView *)textField {
NSInteger keyboardHeight = KEYBOARD_HEIGHT;
if ([textField UITextField.class]) {
keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
}
CGRect screenFrame = [UIScreen mainScreen].bounds;
CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
aRect.size.height -= keyboardHeight;
CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);
if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
[contentSlidingView setContentOffset:scrollPoint animated:YES];
}
}
我们可以为Swift 4.1提供用户给定的代码
let keyBoardSize = 80.0
func keyboardWillShow() {
if view.frame.origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.origin.y < 0 {
viewMovedUp = false
}
}
func keyboardWillHide() {
if view.frame.origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.origin.y < 0 {
viewMovedUp = false
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if sender.isEqual(mailTf) {
//move the main view, so that the keyboard does not hide it.
if view.frame.origin.y >= 0 {
viewMovedUp = true
}
}
}
func setViewMovedUp(_ movedUp: Bool) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
// if you want to slide up the view
let rect: CGRect = view.frame
if movedUp {
rect.origin.y -= keyBoardSize
rect.size.height += keyBoardSize
}
else {
// revert back to the normal state.
rect.origin.y += keyBoardSize
rect.size.height -= keyBoardSize
}
view.frame = rect
UIView.commitAnimations()
}
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}
func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
如果你还在为这件事而挣扎,请阅读我的帖子
我今天提出了一个解决方案。我读过很多关于这个问题的帖子和“教程”,没有一篇在任何情况下都有效(大多数都是相互复制粘贴的)。甚至苹果官方提出的“解决方案”也不起作用,更重要的是,它在横向模式下完全不起作用。苹果公司没有给开发者们解决这样一个常见的基本问题的方法,真是可耻。非常不专业。如此惊人的框架(Cocoa)和如此严重的被低估的问题。
现在,我的解决方案是:让UIScrollView成为您的根视图,然后将所有内容放入其中。然后从这个KeyboardAwareController类子类化视图控制器(您可能需要重新定义scrollView和keyboardPadding方法):
////键盘AwareController.h//社会病////管理员于2014年1月13日创建。//版权所有(c)2014 kuchumovn。保留所有权利。//
#import <UIKit/UIKit.h>
@interface KeyboardAwareController : UIViewController <UITextFieldDelegate>
@end
////键盘AwareController.m//社会病////管理员于2014年1月13日创建。//版权所有(c)2014 kuchumovn。保留所有权利。//
#import "KeyboardAwareController.h"
@interface KeyboardAwareController ()
@end
@implementation KeyboardAwareController
{
CGPoint scrollPositionBeforeKeyboardAdjustments;
__weak UIScrollView* scrollView;
UITextField* activeField;
}
- (id) initWithCoder: (NSCoder*) decoder
{
if (self = [super initWithCoder:decoder])
{
scrollPositionBeforeKeyboardAdjustments = CGPointZero;
}
return self;
}
- (void) viewDidLoad
{
[super viewDidLoad];
}
- (UIScrollView*) scrollView
{
return (UIScrollView*) self.view;
}
- (CGFloat) keyboardPadding
{
return 5;
}
- (void) registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void) deregisterFromKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
- (void) viewWillAppear: (BOOL) animated
{
[super viewWillAppear:animated];
[self registerForKeyboardNotifications];
}
- (void) viewWillDisappear: (BOOL) animated
{
[self deregisterFromKeyboardNotifications];
[super viewWillDisappear:animated];
}
- (void) keyboardWillShow: (NSNotification*) notification
{
//NSLog(@"keyboardWillShow");
// force the animation from keyboardWillBeHidden: to end
scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;
scrollPositionBeforeKeyboardAdjustments = CGPointZero;
}
// warning: i have no idea why this thing works and what does every line of this code mean
// (but it works and there is no other solution on the internets whatsoever)
// P.S. Shame on Apple for missing such a basic functionality from SDK (and many other basic features we have to hack and mess around with for days and nights)
- (void) keyboardDidShow: (NSNotification*) notification
{
//NSLog(@"keyboardDidShow");
UIWindow* window = [[[UIApplication sharedApplication] windows]objectAtIndex:0];
UIView* mainSubviewOfWindow = window.rootViewController.view;
CGRect keyboardFrameIncorrect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrame = [mainSubviewOfWindow convertRect:keyboardFrameIncorrect fromView:window];
CGSize keyboardSize = keyboardFrame.size;
CGRect visibleFrame = CGRectMake(0, 0, 0, 0);
visibleFrame.origin = self.scrollView.contentOffset;
visibleFrame.size = self.scrollView.bounds.size;
CGFloat paddedKeyboardHeight = keyboardSize.height + self.keyboardPadding;
//NSLog(@"visibleFrame %@", NSStringFromCGRect(visibleFrame));
visibleFrame.size.height -= paddedKeyboardHeight;
//NSLog(@"visibleFrame after keyboard height %@", NSStringFromCGRect(visibleFrame));
if (CGRectContainsPoint(visibleFrame, activeField.frame.origin))
return;
scrollPositionBeforeKeyboardAdjustments = scrollView.contentOffset;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height, 0);
contentInsets = UIEdgeInsetsMake(0.0, 0.0, paddedKeyboardHeight, 0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
CGSize scrollContentSize = self.scrollView.bounds.size;
scrollContentSize.height += paddedKeyboardHeight;
self.scrollView.contentSize = scrollContentSize;
//NSLog(@"scrollView %@", NSStringFromCGRect(scrollView.frame));
//NSLog(@"activeField %@", NSStringFromCGRect(activeField.frame));
//[scrollView scrollRectToVisible:activeField.frame animated:YES];
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height);
//NSLog(@"scrollPoint %@", NSStringFromCGPoint(scrollPoint));
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
- (void) keyboardWillBeHidden: (NSNotification*) notification
{
//NSLog(@"keyboardWillBeHidden");
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
// this doesn't work when changing orientation while the keyboard is visible
// because when keyboardDidShow: will be called right after this method the contentOffset will still be equal to the old value
//[scrollView setContentOffset:scrollPositionBeforeKeyboardAdjustments animated:YES];
[UIView animateWithDuration:.25 animations:^
{
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// replacement for setContentOffset:animated:
self.scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;
}];
}
- (void) textFieldDidBeginEditing: (UITextField*) textField
{
activeField = textField;
}
- (void) textFieldDidEndEditing: (UITextField*) textField
{
activeField = nil;
}
@end
如果您有任何问题,我的项目将在github上托管:https://github.com/kuchumovn/sociopathy.ios
为了更好地解释,我还拍了一张截图: