这个问题网络上有很多解决方案,这里只是作为一个纪录。
UIScrollView除了可以解决键盘遮挡的问题,还能动态调节自身的contentSize,其实就是重写addSubview,然后根据子view的坐标来设置contentSize。另外,解决了scrollView嵌套tableView导致的点击冲突问题。
#import <UIKit/UIKit.h>
@interface UIAutoScrollView : UIScrollView
// 重写addSubview,可自动调整contentSize。参数view必须要有高度
-(void)addSubview:(UIView *)view;
@end
#import "UIAutoScrollView.h"
#define KeyboardTopMargin 20.f
@interface UIAutoScrollView () <UIGestureRecognizerDelegate>
{
CGRect _keyboardRect;
CGPoint _previousOffset;
UIEdgeInsets _previousInset;
BOOL _isPreviousSaved;
}
@end
@implementation UIAutoScrollView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
tapGesture.delegate = self;
[tapGesture addTarget:self action:@selector(tapGestureHandle)];
[self addGestureRecognizer:tapGesture];
}
return self;
}
-(void)addSubview:(UIView *)view
{
[super addSubview:view];
// 动态改变contentSize
CGFloat bottom = view.bottom;
if(bottom+KeyboardTopMargin >= self.contentSize.height)
{
self.contentSize = CGSizeMake(self.contentSize.width, bottom+2);
}
}
- (UIView*)findFirstResponderInView:(UIView*)view
{
for (UIView *childView in view.subviews)
{
if ( [childView respondsToSelector:@selector(isFirstResponder)] && [childView isFirstResponder] ) return childView;
UIView *result = [self findFirstResponderInView:childView];
if ( result ) return result;
}
return nil;
}
#pragma mark -点击空白处,隐藏键盘
-(void)tapGestureHandle
{
[self endEditing:YES];
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// 若为UITableViewCellContentView的点击事件,则不截获Touch事件
if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]
&& [gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
return NO;
}
return YES;
}
#pragma mark -Keyboard
-(void)keyboardWillShow:(NSNotification *)notification
{
if(!_isPreviousSaved)// keyboardWillShow根据界面的控件个数,会被多次调用。这里只需要记住初始值
{
_previousOffset = self.contentOffset;
_previousInset = self.contentInset;
}
NSDictionary *userInfo = [notification userInfo];
// 键盘相对于scrollView的位置
CGRect keyboardRect = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardRect = [self convertRect:keyboardRect fromView:nil];
self.contentInset = UIEdgeInsetsMake(0, 0, keyboardRect.size.height, 0);
// 键盘弹起动画时长
NSTimeInterval animationDuration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 当前获取焦点的TextField
UIView *currentResponder = [self findFirstResponderInView:self];
if (currentResponder != nil) {
// TextField左下角相对于scrllView的位置
CGPoint point = [currentResponder convertPoint:CGPointMake(0, currentResponder.height) toView:self];
// 计算textfield左下角到键盘上方的距离
CGFloat scrollY = point.y - (keyboardRect.origin.y - KeyboardTopMargin);
if (scrollY > 0) {
[UIView animateWithDuration:animationDuration animations:^{
// 滚动到对应位置
self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + scrollY);
}];
}
}
}
-(void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
NSTimeInterval animationDuration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
self.contentOffset = _previousOffset;
self.contentInset = _previousInset;
_isPreviousSaved = NO;
}];
}
@end