当我正在使用iOS本机应用上的login screen
时,应用程序工作得非常好,直到ios 10.在iOS 11之后topLayoutGuide
和bottomLayoutGuide
,我已将其替换为safeAreaLayoutGuide
。
但它仍然没有解决我的问题,当键盘弹出时,由于页脚视图,它会导致视图的无限滚动。 我的视图层次结构是
ScrollView
Username and Password fields with Login button
FooterEmptyView
Footer Label
在FooterEmptyView
中我有一个约束,只是为了从登录按钮腾出空间直到Footer Label
,这将根据设备的大小增加或减少。
所有约束都以编程方式放置。
UIScrollView是否需要关注iOS 11? 在此先感谢!!
答案 0 :(得分:1)
您提供的回购不包含您问题中描述的大部分功能。键盘事件就是其中之一。在运行代码的同时,我还得到了错误日志,这些约束存在冲突,因此至少在运行时已删除它们。此外,发布的应用程序根本不做任何事情,或者显示除了显示2个文本字段和按钮之外应该做什么。
由于您创建了一个新项目,您所做的就是修改了自动生成的视图控制器,因此没有理由不将此代码添加到您的问题中,而不是发布指向您的存储库的链接。
我仍然检查了你的代码并试图扣除你正在做的事情,并发现我对你的约束没有任何意义。也许至少一些评论会有所帮助。然后我重新创建了你的系统,在滚动视图上放置2个文本字段和一个带有约束的按钮。我还添加了可以移动字段的方法,以便它们从底部正确偏移,设计用于键盘框架更改时的事件。
我希望代码可以帮助您解决问题。完成后请删除此问题。
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *scrollViewContentView;
@property (nonatomic, strong) UITextField *usernameTextField;
@property (nonatomic, strong) UITextField *passwordTextField;
@property (nonatomic, strong) UIButton *loginButton;
@property (nonatomic, strong) NSLayoutConstraint *usernameBottomConstraint; // Restrict for keyboard
@property (nonatomic, strong) NSLayoutConstraint *passwordBottomConstraint; // Restrict for keyboard
@end
@implementation ViewController
- (UIScrollView *)scrollView {
// Lazy load
if(_scrollView == nil) {
_scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:_scrollView];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self attachBorderConstraint:_scrollView to:self.view];
}
return _scrollView;
}
- (UIView *)scrollViewContentView {
// Lazy load
if(_scrollViewContentView == nil) {
_scrollViewContentView = [[UIView alloc] initWithFrame:self.view.bounds];
[self.scrollView addSubview:_scrollViewContentView];
_scrollViewContentView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:_scrollViewContentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.scrollView attribute:NSLayoutAttributeTop multiplier:1.0 constant:10.0];
topConstraint.priority = (UILayoutPriority)800; // Needs a bit lower constraints when keyboard shows and the whole thing goes a bit off the screen
[self.scrollView addConstraint:topConstraint];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:_scrollViewContentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.scrollView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:10.0]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:_scrollViewContentView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.scrollView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10.0]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:_scrollViewContentView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.scrollView attribute:NSLayoutAttributeRight multiplier:1.0 constant:10.0]];
}
return _scrollViewContentView;
}
- (void)viewDidLoad {
[super viewDidLoad];
// TODO: remove testing offsets gesture and its method
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTestGesture)]];
// Set some colors for debugging and to see what happens. Later remove these
self.scrollView.backgroundColor = [UIColor redColor];
self.scrollViewContentView.backgroundColor = [UIColor greenColor];
CGFloat margins = 20.0f;
CGFloat fieldHeight = 44.0f;
CGFloat separatorHeight = 12.0f;
// Username text field
{
UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(0, margins, self.view.frame.size.width-margins*2.0, fieldHeight)];
field.placeholder = @"Enter User Name";
field.backgroundColor = [UIColor whiteColor];
field.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollViewContentView addSubview:field];
// We want it on top of content view and have fixed offset from borders
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:margins]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:margins]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeRight multiplier:1.0 constant:-margins]];
[field addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:fieldHeight]];
self.usernameTextField = field;
}
// Password text field
{
UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(0, margins, self.view.frame.size.width-margins*2.0, fieldHeight)];
field.placeholder = @"Enter Password";
field.backgroundColor = [UIColor whiteColor];
field.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollViewContentView addSubview:field];
// We want it below username field and have fixed offset from borders
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.usernameTextField attribute:NSLayoutAttributeBottom multiplier:1.0 constant:separatorHeight]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:margins]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeRight multiplier:1.0 constant:-margins]];
[field addConstraint:[NSLayoutConstraint constraintWithItem:field attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:fieldHeight]];
self.passwordTextField = field;
}
// Login button
{
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, margins, self.view.frame.size.width-margins*2.0, 50.0)];
[button setTitle:@"Login" forState:UIControlStateNormal];
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:16.0]; //[UIFont fontWithName:@"MarkerFelt-Thin" size:16];
button.translatesAutoresizingMaskIntoConstraints = NO;
button.backgroundColor = [UIColor whiteColor];
[self.scrollViewContentView addSubview:button];
// We want it below password field and have fixed offset from borders
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.passwordTextField attribute:NSLayoutAttributeBottom multiplier:1.0 constant:separatorHeight]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:margins]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeRight multiplier:1.0 constant:-margins]];
[button addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:50.0]];
[self.scrollViewContentView addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.scrollViewContentView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-margins]];
self.loginButton = button;
}
// Now to position the content view insde scroll view
// Horizontally we want to constrain it to borders and restrict maximum width:
{
// Must be centered
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewContentView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0];
[self.scrollView addConstraint:constraint];
}
{
// Constraint width
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewContentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:400.0];
constraint.priority = (UILayoutPriority)500; // Low priority so it will shrink when screen width will be too low
[self.scrollViewContentView addConstraint:constraint];
}
// Vertically we want to constrain it to borders and restrict maximum width:
{
// Must be centered
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewContentView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0];
constraint.priority = (UILayoutPriority)500;
[self.scrollView addConstraint:constraint];
}
{
// Constraint height
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewContentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:400.0];
constraint.priority = (UILayoutPriority)200; // Low priorty so it will autosize
[self.scrollViewContentView addConstraint:constraint];
}
self.usernameBottomConstraint = [NSLayoutConstraint constraintWithItem:self.usernameTextField attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-0];
self.passwordBottomConstraint = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-0];
[self.view addConstraints:@[self.usernameBottomConstraint, self.passwordBottomConstraint]];
}
- (void)onTestGesture {
static int testState = 0;
testState++;
switch (testState%3) {
case 0:
// Keyboard hidden
[self restrictUsernameBottomOffsetTo:0.0];
[self restrictPasswrodBottomOffsetTo:0.0];
break;
case 1:
// Keyboard shown for username
[self restrictUsernameBottomOffsetTo:350.0];
break;
case 2:
// Keyboard shown for password
[self restrictPasswrodBottomOffsetTo:350.0];
break;
default:
break;
}
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)restrictUsernameBottomOffsetTo:(CGFloat)newOffset {
self.passwordBottomConstraint.constant = -0.0f;
self.usernameBottomConstraint.constant = -newOffset;
}
- (void)restrictPasswrodBottomOffsetTo:(CGFloat)newOffset {
self.usernameBottomConstraint.constant = -0.0f;
self.passwordBottomConstraint.constant = -newOffset;
}
- (NSArray<NSLayoutConstraint *> *)attachBorderConstraint:(UIView *)subview to:(UIView *)superview {
NSMutableArray *constraints = [[NSMutableArray alloc] init];
[constraints addObject:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];
[superview addConstraints:constraints];
return constraints;
}
@end