UIScrollview 是否与 UIStatusbar 一起正常工作?
Does UIScrollview works correct with UIStatusbar?
我的问题与 UIScrollview 有关。让我们描述一下,
我有一个带有滚动视图的注册屏幕,最初没有启用滚动。当键盘出现时,我将启用滚动视图,当键盘再次隐藏时,我将禁用滚动。我的滚动视图的宽度和高度与其默认视图相同,我在容器中应用了水平和垂直中心以及顶部、底部、前导和尾部边缘为零(即它等于默认视图)。我有一个导航到注册屏幕的注册按钮,并应用了底部约束(底部 space 约束 = 0),我还使用键盘通知来显示和隐藏。
实际问题:
当点击文本字段键盘出现时,滚动视图滚动,当我关闭键盘时,滚动视图下降,但这次注册按钮会向上移动一点点(比如底部 space 有 20 点限制)。
第一次在状态栏之后启动类似的滚动视图,但是当键盘出现和隐藏时,类似的滚动视图在包括状态栏的视图上呈现。
我是否需要在 IB 中添加任何与 Top/Bottom Layout Guide
相关的约束?
或者我是否需要添加与 viewDidLoad
相关的任何约束
键盘通知代码。
-(void)keyboardWillShow:(NSNotification *)notification {
[self.navigationController.navigationBar setBackgroundImage:nil
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = nil;
self.ContentScrollView.scrollEnabled=YES;
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.ContentScrollView convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(self.ContentScrollView.frame, keyboardFrameInView);
UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compatibility between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0.0 options:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] animations:^{
self.ContentScrollView.contentInset = newContentInsets;
self.ContentScrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _activeField should either be the input field (UITextField,..) or another element
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _activeField in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
*/
if (_activeField) {
CGRect controlFrameInScrollView = [self.ContentScrollView convertRect:_activeField.bounds fromView:_activeField]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, 0); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = (controlFrameInScrollView.origin.y - self.ContentScrollView.contentOffset.y)+10;
CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = self.ContentScrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
// scroll up until the control is in place
CGPoint newContentOffset = self.ContentScrollView.contentOffset;
newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
CGFloat maxScrollViewHeight = MAX(self.ContentScrollView.frame.size.height, self.ContentScrollView.contentSize.height);
newContentOffset.y = MIN(newContentOffset.y, maxScrollViewHeight - scrollViewVisibleHeight);
[self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
} else if (controlFrameInScrollView.origin.y < self.ContentScrollView.contentOffset.y) {
// if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
CGPoint newContentOffset = self.ContentScrollView.contentOffset;
newContentOffset.y = controlFrameInScrollView.origin.y;
[self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
}
}
} completion:NULL];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
[UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]doubleValue ] delay:0.01 options:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]intValue] animations:^{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.ContentScrollView.contentInset = contentInsets;
self.ContentScrollView.scrollIndicatorInsets = contentInsets;
CGPoint scrollPoint;
self.ContentScrollView.scrollEnabled=NO;
scrollPoint = CGPointMake(0.0, 0.0);
[self.ContentScrollView setContentOffset:scrollPoint animated:YES];
} completion:^(BOOL finished){
__weak typeof(self) weakSelf=self;
[weakSelf.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
weakSelf.navigationController.navigationBar.shadowImage = [UIImage new];
}];
}
图片
如果进一步需要,我将发送键盘通知前后的屏幕截图。
谢谢。
A Boolean value that indicates whether the view controller should
automatically adjust its scroll view insets.
声明
@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets
讨论
Default value is YES, which allows the view controller to adjust its
scroll view insets in response to the screen areas consumed by the
status bar, navigation bar, and toolbar or tab bar. Set to NO if you
want to manage scroll view inset adjustments yourself, such as when
there is more than one scroll view in the view hierarchy.
在viewDidLoad
中写入self. automaticallyAdjustsScrollViewInsets=NO;
并尝试
我的问题与 UIScrollview 有关。让我们描述一下,
我有一个带有滚动视图的注册屏幕,最初没有启用滚动。当键盘出现时,我将启用滚动视图,当键盘再次隐藏时,我将禁用滚动。我的滚动视图的宽度和高度与其默认视图相同,我在容器中应用了水平和垂直中心以及顶部、底部、前导和尾部边缘为零(即它等于默认视图)。我有一个导航到注册屏幕的注册按钮,并应用了底部约束(底部 space 约束 = 0),我还使用键盘通知来显示和隐藏。
实际问题: 当点击文本字段键盘出现时,滚动视图滚动,当我关闭键盘时,滚动视图下降,但这次注册按钮会向上移动一点点(比如底部 space 有 20 点限制)。
第一次在状态栏之后启动类似的滚动视图,但是当键盘出现和隐藏时,类似的滚动视图在包括状态栏的视图上呈现。
我是否需要在 IB 中添加任何与 Top/Bottom Layout Guide
相关的约束?
或者我是否需要添加与 viewDidLoad
键盘通知代码。
-(void)keyboardWillShow:(NSNotification *)notification {
[self.navigationController.navigationBar setBackgroundImage:nil
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = nil;
self.ContentScrollView.scrollEnabled=YES;
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.ContentScrollView convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(self.ContentScrollView.frame, keyboardFrameInView);
UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compatibility between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0.0 options:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] animations:^{
self.ContentScrollView.contentInset = newContentInsets;
self.ContentScrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _activeField should either be the input field (UITextField,..) or another element
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _activeField in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
*/
if (_activeField) {
CGRect controlFrameInScrollView = [self.ContentScrollView convertRect:_activeField.bounds fromView:_activeField]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, 0); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = (controlFrameInScrollView.origin.y - self.ContentScrollView.contentOffset.y)+10;
CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = self.ContentScrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
// scroll up until the control is in place
CGPoint newContentOffset = self.ContentScrollView.contentOffset;
newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
CGFloat maxScrollViewHeight = MAX(self.ContentScrollView.frame.size.height, self.ContentScrollView.contentSize.height);
newContentOffset.y = MIN(newContentOffset.y, maxScrollViewHeight - scrollViewVisibleHeight);
[self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
} else if (controlFrameInScrollView.origin.y < self.ContentScrollView.contentOffset.y) {
// if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
CGPoint newContentOffset = self.ContentScrollView.contentOffset;
newContentOffset.y = controlFrameInScrollView.origin.y;
[self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
}
}
} completion:NULL];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
[UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]doubleValue ] delay:0.01 options:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]intValue] animations:^{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.ContentScrollView.contentInset = contentInsets;
self.ContentScrollView.scrollIndicatorInsets = contentInsets;
CGPoint scrollPoint;
self.ContentScrollView.scrollEnabled=NO;
scrollPoint = CGPointMake(0.0, 0.0);
[self.ContentScrollView setContentOffset:scrollPoint animated:YES];
} completion:^(BOOL finished){
__weak typeof(self) weakSelf=self;
[weakSelf.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
weakSelf.navigationController.navigationBar.shadowImage = [UIImage new];
}];
}
图片
如果进一步需要,我将发送键盘通知前后的屏幕截图。
谢谢。
A Boolean value that indicates whether the view controller should automatically adjust its scroll view insets.
声明
@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets
讨论
Default value is YES, which allows the view controller to adjust its scroll view insets in response to the screen areas consumed by the status bar, navigation bar, and toolbar or tab bar. Set to NO if you want to manage scroll view inset adjustments yourself, such as when there is more than one scroll view in the view hierarchy.
在viewDidLoad
中写入self. automaticallyAdjustsScrollViewInsets=NO;
并尝试