现在的位置: 首页 > 综合 > 正文

ios键盘弹出挡住带自定义UITableViewCell的UITableView的解决方法

2017年12月09日 ⁄ 综合 ⁄ 共 3754字 ⁄ 字号 评论关闭

案例:

需要做一个UITableView,其包含两个section,其中一个section中的cell是UITableViewCell类对象,另一个section中的cell是自定义的Cell类对象,自定义的Cell是一个表单,里面包含有多个UITextField。

遇到的问题:

当我点击的UITextField,系统弹出键盘的时候,所有的UITextField控件都被弹出的键盘挡住了。

解决思路:

在点击了UITextField控件,弹出键盘的时候,把整个tableView向上移动一段距离,等结束输入之后,就把整个tableView移动回来

步骤:

1.捕获点中UITextField控件的事件

因为我的控件是在自定义的UITableViewCell中的,所以,我在自定义的UITableViewCell字类,假设是ACell中定义了一个方法-(IBAction)beginEditting:(id)sender,用于相应点中UITextField控件事件,因为点中UITextField事件会发出EditingDidBegin事件,所以根据这个事件连接上上述定义的方法,那么在点中UITextField控件的时候,就会自动调用上述的方法。

2.移动tableView

这时问题是,在方法中,我们怎么能控制到tableView移动呢?因为当前代码是在自定义类中编写的,无法直接调用到tableView对象。我们可以通过获取上级View的办法来获取到包含这个自定义cell的TableView,也就时superView,一个View调用superView方法,就能够获取到包含自身的View的对象。但是这里要注意,因为UITextField自己本身也是一个View,所以要获取到tableView,我们需要执行textField.superView.superView,因为第一个superView得到的时包含了这个UITextField的Cell,再调用superView,才得到包含这个Cell得TableView。

获取到tableView对象后,想对它进行移动就很容易了,只要获取到tableView得frame,然后改变它origin得x,y值,然后修改好之后再赋值回去,就可以移动它的位置了。

3.动画移动tableView

移动tableView可能很容易就可以实现,但是总会令人觉得不舒服,因为在键盘弹出的时候,tableView闪一下就移动到指定的位置中去了,非常不美观。所以这里用动了动画的方式,让tableView滑动到指定的地方,这里的动画也很简单,就三句代码,由于本人还没认真去了解动画,所以在此就不求甚解了。使用动画滑动的代码如下:

    [UIView beginAnimations:@"moveView" context:nil];
    [UIView setAnimationDuration:0.3];//移动的速度
    parentView.frame = frame;//移动后的位置,其他修改也是写到这个位置
    [UIView commitAnimations];

-(IBAction)beginEditting:(id)sender的完整实现如下:

- (void)beginEditting:(id)sender
{
    
    UIView *parentView = self.superview.superview;
    CGRect frame = parentView.frame;
    frame.origin.y -= frame.size.height*0.3;
    [UIView beginAnimations:@"moveView" context:nil];
    [UIView setAnimationDuration:0.3];
    parentView.frame = frame;
    [UIView commitAnimations];
}

在自定义UITableViewCell类中写好这个方法,并在Interface Builder中连好线,就可以实现点击自定义UITableViewCell,键盘弹出来的时候,tableView会向上滑动一段距离了。

4.输入完毕,点击非UITextField类的控件时,键盘退回,tableView滑回原本的位置

这时想到的方法就是给当前的view添加一个点击的手势tap(网上有人说要用tableView的background来处理手势,其实过程一样,等下会解释),当用户tap了一下view的时候,就退回键盘,并把tableView移动回原来的位置,所以自定义了一个手势,方法如下:

    UITapGestureRecognizer *tap = [[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapOnce)]autorelease];
    [tap setNumberOfTapsRequired:1];
    tap.delegate = self;
    [self.view addGestureRecognizer:tap];

而点击的响应方法如下:

- (void)tapOnce
{
    CGRect frame = self.costFormTableView.frame;
    if (frame.origin.y == 0) {     //防止view在正常状态下也被移动
        return ;
    }
    frame.origin.y += frame.size.height*0.3;
    [UIView beginAnimations:@"moveView" context:nil];
    [UIView setAnimationDuration:0.3];
    self.costFormTableView.frame = frame;
    [UIView commitAnimations];
}

这时,点击的tableView,可以捕获到tap事件,自己的在相应的响应方法内打印一些信息出来判断,但是,tableView被来含有的一些cell点击后就没有反应了。

5.解决点中tableViewCell,点击事件被手势事件截获的现象。

本人测试过,如上面所说,就算事给tableView的background添加手势,也一样会屏蔽掉tableViewCell的点击响应,所以解决的办法,是判断点击到的控件的类型,如果点中的控件的类型是tableViewCell的话,就让自定义的手势不生效。这时就要在使当前类实现UIGestureRecognizerDelegate协议,然后重写一下方法:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    NSLog(@"%@",NSStringFromClass(touch.view.class)); //可以用这个方法来判断自己点中的控件使什么类型,然后用下面的if语句处理
    if ([NSStringFromClass(touch.view.class) isEqualToString:@"UITableViewCellContentView"])
    {
        if (self.costFormTableView.frame.origin.y != 0) {  //这里使防止tableView上移后,屏幕上的内容刚好之后Cell和键盘,这样点击Cell中的非UITextField控件一样可以使tableView移动回原来的位置
            return YES;
        }
        return NO;
    }
    return YES;
}

这时,点中tableViewcell对象的时候,就能响应其原来的事件而不会被自定义的tap手势屏蔽掉了。

6.最后一个问题,当tableView移动到原本的位置的时候,键盘还保留在页面上。

使键盘退回的方法,网上提到的都是用控件调用resignFirstResponder的方法,但是在这个案例中,感觉有点麻烦,被人也试过使用这种方法,但是不知道使操作错误还是其他原因,都无法实现。但是在一次无意的尝试中,发现调用tableView的reloadData时,键盘回退回,所以修改上述的手势响应方法,如下:

- (void)tapOnce
{
    CGRect frame = self.costFormTableView.frame;
    if (frame.origin.y == 0) {
        return ;
    }
    frame.origin.y += frame.size.height*0.425;
    [UIView beginAnimations:@"moveView" context:nil];
    [UIView setAnimationDuration:0.3];
    self.costFormTableView.frame = frame;
    [self.costFormTableView reloadData];   //加上这一句
    [UIView commitAnimations];
}

估计时因为reloadData的时候,tableView中的控件都会重新加载数据,在此同时所有控件都失去了firstResponder,所以键盘就自动退回去了。

到此,这个案例就完成了。

抱歉!评论已关闭.