web-dev-qa-db-ja.com

UITableViewを取得して、選択したUITextFieldまでスクロールし、キーボードに隠れないようにします

UITextFieldのテーブルビューにUIViewControllerがあります(UITableViewControllerではありません)。テーブルビューがUITableViewControllerにある場合、テーブルはキーボードで非表示にならないように、編集中のtextFieldに自動的にスクロールします。しかし、UIViewControllerではそうではありません。

私はこれを達成するために複数の方法で数日間読んでみましたが、機能しません。実際にスクロールする最も近いものは次のとおりです。

-(void) textFieldDidBeginEditing:(UITextField *)textField {

// SUPPOSEDLY Scroll to the current text field

CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];

}

ただし、これはテーブルを一番上の行までスクロールするだけです。簡単なタスクのように思えるのは、数日間のフラストレーションです。

私は以下を使用してtableViewセルを構築しています:

- (UITableViewCell *)tableView:(UITableView *)aTableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];

UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc] 
        initWithStyle:UITableViewCellStyleDefault 
        reuseIdentifier:identifier] autorelease];

        cell.accessoryType = UITableViewCellAccessoryNone;

        UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];

        theTextField.adjustsFontSizeToFitWidth = YES;
        theTextField.textColor = [UIColor redColor];
        theTextField.text = [textFieldArray objectAtIndex:indexPath.row];
        theTextField.keyboardType = UIKeyboardTypeDefault;
        theTextField.returnKeyType = UIReturnKeyDone;
        theTextField.font = [UIFont boldSystemFontOfSize:14];
        theTextField.backgroundColor = [UIColor whiteColor];
        theTextField.autocorrectionType = UITextAutocorrectionTypeNo;
        theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
        theTextField.clearsOnBeginEditing = NO;
        theTextField.textAlignment = UITextAlignmentLeft;

        //theTextField.tag = 0;
        theTextField.tag=indexPath.row;

        theTextField.delegate = self;

        theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
        [theTextField setEnabled: YES];

        [cell addSubview:theTextField];

        [theTextField release];


}

return cell;
}

何らかの方法でtextFieldDidBeginEditingメソッドでindexPath.rowを渡すことができれば、tableViewを適切にスクロールできると思いますか?

どんな助けも大歓迎です。

46

私のアプリでは、contentInsetscrollToRowAtIndexPathの組み合わせを次のように使用しています。

キーボードを表示したい場合は、希望する高さのテーブルとともに、下部にcontentInsetを追加するだけです。

tableView.contentInset =  UIEdgeInsetsMake(0, 0, height, 0);

その後、安全に使用できます

[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES];

ContentInsetを追加することにより、最後のセルにフォーカスしている場合でも、tableViewはスクロールできます。キーボードを閉じるときは、contentInsetをリセットしてください。

編集:
セクションが1つのみの場合(cell_section with 0)およびtextViewタグを使用してセル行に通知します。

これを確認してください ITableViewでキーボードの上にUITextFieldをスクロールOR UIScrollView

108
Andrei Stanescu
- (void)keyboardWillShow:(NSNotification *)sender
{
    CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
    NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
        UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0);
        tableView.contentInset = edgeInsets;
        tableView.scrollIndicatorInsets = edgeInsets;
    } completion:nil];
}

- (void)keyboardWillHide:(NSNotification *)sender
{
    NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
        UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
        tableView.contentInset = edgeInsets;
        tableView.scrollIndicatorInsets = edgeInsets;
    } completion:nil];
}

そして-(void)viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

それから

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
46
FunkyKat

これはFunkyKatの答えの微調整です(FunkyKatに感謝します!)。将来のiOS互換性のために、UIEdgeInsetsZeroをハードコーディングしないことはおそらく有益でしょう。

代わりに、現在のインセット値を要求し、必要に応じてボトム値を微調整します。

- (void)keyboardWillShow:(NSNotification *)sender {
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width;
    if (isIOS8()) height = kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = [[self tableView] contentInset];
        edgeInsets.bottom = height;
        [[self tableView] setContentInset:edgeInsets];
        edgeInsets = [[self tableView] scrollIndicatorInsets];
        edgeInsets.bottom = height;
        [[self tableView] setScrollIndicatorInsets:edgeInsets];
    }];
}

- (void)keyboardWillHide:(NSNotification *)sender {
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = [[self tableView] contentInset];
        edgeInsets.bottom = 0;
        [[self tableView] setContentInset:edgeInsets];
        edgeInsets = [[self tableView] scrollIndicatorInsets];
        edgeInsets.bottom = 0;
        [[self tableView] setScrollIndicatorInsets:edgeInsets];
    }];
}
10
bmauter

この問題に遭遇した他の誰かのために、必要なメソッドをここに投稿しています。

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];

    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc]  initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];

        UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];

        theTextField.keyboardType = UIKeyboardTypeDefault;
        theTextField.returnKeyType = UIReturnKeyDone;
        theTextField.clearsOnBeginEditing = NO;
        theTextField.textAlignment = UITextAlignmentLeft;

        // (The tag by indexPath.row is the critical part to identifying the appropriate
        // row in textFieldDidBeginEditing and textFieldShouldEndEditing below:)

        theTextField.tag=indexPath.row;

        theTextField.delegate = self;

        theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
        [theTextField setEnabled: YES];

        [cell addSubview:theTextField];

        [theTextField release];

    }

    return cell;
}

-(void) textFieldDidBeginEditing:(UITextField *)textField {

    int z = textField.tag;                                              

    if (z > 4) {

        // Only deal with the table row if the row index is 5 
        // or greater since the first five rows are already 
        // visible above the keyboard   

        // resize the UITableView to fit above the keyboard

        self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0);       

        // adjust the contentInset

        wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10);        

        // Scroll to the current text field

        [wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    }
}


- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {

    // Determine which row is being edited

    int z = textField.tag;  

    if (z > 4) {

        // resize the UITableView to the original size

        self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0);       

        // Undo the contentInset
        wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);         

    }

    return YES;

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {

    // Dismisses the keyboard when the "Done" button is clicked

    [textField resignFirstResponder];

    return YES;                                 

}
8

私のコーディングを試してください、これはあなたのために役立ちます

tabelview.contentInset =  UIEdgeInsetsMake(0, 0, 210, 0);
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section]
                 atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
1

私は簡単な解決策が必要だったので helped

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        let pointInTable = textField.superview!.convert(textField.frame.Origin, to: tableView)
        var tableVContentOffset = tableView.contentOffset
        tableVContentOffset.y = pointInTable.y
        if let accessoryView = textField.inputAccessoryView {
            tableVContentOffset.y -= accessoryView.frame.size.height
        }
        tableView.setContentOffset(tableVContentOffset, animated: true)
        return true;
    }

enter image description here

1
Nik Kov

Appleには、UITableViewControllerで行うのと同様にこれを自然に行う方法を説明する公式投稿があります。 Stackoverflowの回答では、これをSwiftバージョンと一緒に説明しています。

https://stackoverflow.com/a/31869898/1032179

1

私のコード。たぶん誰かが役に立つでしょう:tableViewのカスタムtextFieldセル

.m

    @property (nonatomic, strong) UITextField *currentCellTextField;

       CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
            if (cell == nil) {
                NSArray * nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
                cell = (CustomCell *)[nib objectAtIndex:0];
                cell.textfield.delegate = self;
            }
      - (void) textFieldDidBeginEditing:(UITextField *)textField
 {
  self.currentCellTextField = textField;

  CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.Origin fromView:textField];
  NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];

if (path.section >= 2) {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];
    self.organisationTableView.contentInset = UIEdgeInsetsMake(0, 0, kOFFSET_FOR_KEYBOARD, 0);
    CGPoint siize = self.organisationTableView.contentOffset;
    siize.y =(pnt.y-170);
    self.organisationTableView.contentOffset = CGPointMake(0, siize.y);
    [UIView commitAnimations];
    }
 }

  -(BOOL)textFieldShouldReturn:(UITextField *)textField
  {
   [textField resignFirstResponder];

CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.Origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];

 if (path.section >= 2) {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];
    self.organisationTableView.contentInset = UIEdgeInsetsZero;
    self.organisationTableView.contentOffset = CGPointMake(0, self.organisationTableView.contentOffset.y);
    [UIView commitAnimations];
      }

 return YES;
   }
0
Vadim Shevchik

私の場合、UITableviewは別のUIView内にあり、そのUIvieはメインのUIScrollviewにありました。そのため、この種の問題にはより一般的なソリューションを使用しました。特定のUIScrollViewでセルのY座標を見つけ、正しいポイントまでスクロールしました。

-(void)textFieldDidBeginEditing:(UITextField *)textField{
float kbHeight = 216;//Hard Coded and will not support lanscape mode
UITableViewCell *cell = (UITableViewCell *)[textField superview];
float scrollToHeight = [self FindCordinate:cell];
[(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES];
}

-(float)FindCordinate:(UIView *)cell{
float Ycordinate = 0.0;
while ([cell superview] != self.view) {
    Ycordinate += cell.frame.Origin.y;
    cell = [cell superview];
}
Ycordinate += cell.frame.Origin.y;
return Ycordinate;
}
0
Mike.R

テーブルビューだけでなく、UITableControllerをUIViewControllerに追加してみてください。この方法で、UITableViewControllerのviewWillAppearを呼び出すと、すべてが機能しているように見えます。

例:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [tableViewController viewWillAppear:animated];
}
0
colin lamarre

別の簡単な解決策は、最後のテーブルセクションのフッター用にスペースを追加することです。

- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    if (section == lastSection) {
        return keyboard height;
    }
    return 0;
}

この領域にもアイコンを追加できます。 :)

0
thanhbinh84

@FunkyKatと@bmauterの回答に小さな機能を追加しました(ところで、素晴らしい回答です。受け入れられるべきです)。

通常のTable View Edgeインセットは、キーボード出現の前後に保存されます。

- (void)keyboardWillShow:(NSNotification *)sender
{
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = self.tableView.contentInset;
        edgeInsets.bottom += height;
        self.tableView.contentInset = edgeInsets;
        edgeInsets = self.tableView.scrollIndicatorInsets;
        edgeInsets.bottom += height;
        self.tableView.scrollIndicatorInsets = edgeInsets;
    }];
}

- (void)keyboardWillHide:(NSNotification *)sender
{
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = self.tableView.contentInset;
        edgeInsets.bottom -= height;
        self.tableView.contentInset = edgeInsets;
        edgeInsets = self.tableView.scrollIndicatorInsets;
        edgeInsets.bottom -= height;
        self.tableView.scrollIndicatorInsets = edgeInsets;
    }];
}
0

TableView自体のサイズを変更して、キーボードの下に移動しないようにする必要があります。

-(void) textFieldDidBeginEditing:(UITextField *)textField {

// SUPPOSEDLY Scroll to the current text field
self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard);
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];

}

または、キーボード通知を使用できます。より多くの情報を持っているため、これはわずかに良く機能し、キーボードがいつ来るかを知るという点でより一貫しています:

//ViewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

そして実装します:

- (void)keyboardWillShow:(NSNotification *)notification {

}
- (void)keyboardWillHide:(NSNotification *)notification {

}
0
GendoIkari