エンジニアリングにはほど遠い

iPhoneアプリとかサイトとかをつくっていくブログです。

キーボードでUIパーツが隠れるのをUIScrollViewにて上にスクロールして回避

昔からなされている事だとは思いますが、今日初めてその問題に突き当たったので。

Appleの公式のやり方だとなんか動かなかったので少しだけ別のやり方で。

考え方として、見せたいUIパーツの下の部分がキーボードに隠れた時に、隠れた分だけ上に上げる、ということでしょう。
で、このUIパーツの下の部分なんですが、ややこしいので絶対座標で考えようと思います。

で、絶対座標についてはこちらを参考にさせていただきました。この方法だと、status barがあろうと、navigation barがあろうとなかろうと、画面の一番上からの位置が出せました。

これをpartsAbsBottomPointとしました。

f:id:J_ogawa:20140403005039p:plain

位置関係的にこういう感じなので(汚ねえ・・)、

partsAbsBottomPoint.y > (window height) - (keyboard height)

このときに隠れるということになります。隠れる分は partsAbsBottomPoint.y - (window.height - keyboard.height) 。

コード的にこういう感じでしょうか。

float overlapValue = partsAbsBottomPoint.y - (window.height - keyboard.height)
if (overlapValue > 0) {
  overlapValue分だけスライドさせる
}

その結果

- (CGPoint)absPoint:(UIView *)view
{
    CGPoint ret = CGPointMake(view.frame.origin.x, view.frame.origin.y);
    if ([view superview] != nil)
    {
        CGPoint addPoint = [self absPoint:[view superview]];
        ret = CGPointMake(ret.x + addPoint.x, ret.y + addPoint.y);
    }
    return ret;
}

// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)notification
{
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    //UIKeyboardFrameEndUserInfoKey: better when conversion candidates appear
  
    CGPoint partsAbsOrigin = [self absPoint:_showParts];
    CGPoint partsAbsBottomPoint = (CGPoint){ partsAbsOrigin.x, partsAbsOrigin.y + _showParts.frame.size.height };
    
    float overlapValue = partsAbsBottomPoint.y - ([[UIApplication sharedApplication] keyWindow].frame.size.height - keyboardSize.height);
    
    if (overlapValue > 0){
        CGPoint scrollPoint = CGPointMake(0.0, overlapValue);
        [_rootScrollView setContentOffset:scrollPoint animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    [_rootScrollView setContentOffset:CGPointZero animated:YES];
}

_showPartsには見せたいパーツのインスタンスを入れる。

#pragma mark UITextViewDelegate

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    self.showParts = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    self.showParts = nil;
}

github
サブクラスにして使ってみてます。

しかしまだTableView上のフォームはうまく対応できていない。