iOS解决键盘遮挡问题

    这个问题网络上有很多解决方案,这里只是作为一个纪录。


    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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值