web-dev-qa-db-ja.com

キーボードが表示されたときにビューを上にスクロールする方法は?

私はこの質問が何度も何度も尋ねられていることを知っていますが、何も私のために働いていないようです。周囲のソリューションのほとんどはかなり古く、残りは実際のプロジェクトのコーディングの10倍の非常に大きなコードブロックです。いくつかのUITextFieldが縦に並んでいますが、キーボードを起動して編集すると、テキストフィールドが隠されます。ビューを上にスクロールし、編集の開始と終了時に下に戻る簡単な初心者向けの方法があるかどうか疑問に思っていましたか?

ありがとうございました。

37
Henry F

キーボード通知と現在のファーストレスポンダーの検出を使用して、スクロールビューと非スクロールビューで動作するソリューションを作成しましたが、代わりにこの単純なソリューションを使用することがあります。テキストフィールドデリゲートのtextViewDidBeginEditing:メソッドを使用して、ビュー全体を上に移動します。これを行う最も簡単な方法は、self.view.bounds.Origin.yを-100(またはその他)に変更するという方法を使用することです。対応するtextViewShouldEndEditing:メソッドを使用して、反対の値(この場合は100)に設定します。 boundsの変更は相対的な手順です。変更後、フレームは移動しますが、境界の原点はまだゼロです。

29
Peter DeWeese

見つかったので、TPKeyboardAvoidingを使用します- https://github.com/michaeltyson/TPKeyboardAvoiding

うまく機能し、セットアップも非常に簡単です。

  • UIScrollViewをView Controllerのxibに追加します
  • スクロールビューのクラスをTPKeyboardAvoidingScrollViewに設定します(xibで、IDインスペクターを使用して)
  • そのスクロールビュー内にすべてのコントロールを配置します

必要に応じて、プログラムで作成することもできます。


UITableViewController内に同じニーズのクラスがあります。 4.3未満のバージョンのiOSをサポートする場合にのみ必要です。

25
Guillaume

@BenLuおよび関数の問題に直面している他のユーザーが呼び出されることはありません。理由は次のとおりです。

 -(void)textFieldDidBeginEditing:(UITextField *)textField
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35f];
    CGRect frame = self.view.frame;
    frame.Origin.y = -100;
    [self.view setFrame:frame];
    [UIView commitAnimations];
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35f];
    CGRect frame = self.view.frame;
    frame.Origin.y = 100;
    [self.view setFrame:frame];
    [UIView commitAnimations];
}

私はこの問題にしばらく時間を費やし、コードを集めて最終的なソリューションを作成しました。私の問題は、UITableViewのスクロールとキーボードの開閉に関連していました。

セルクラスには2つの部分メソッドが必要です。

    void EditingBegin(UITextField sender)
    {
        // Height of tallest cell, you can ignore this!
        float tableMargin = 70.0f;
        float tableHeight = _tableView.Frame.Size.Height;
        float keyBoardHeight = KeyboardHeight();

        NSIndexPath[] paths = this._tableView.IndexPathsForVisibleRows;
        RectangleF rectLast = this._tableView.RectForSection(paths[paths.Length - 1].Section);
        RectangleF rectFirst = this._tableView.RectForSection(paths[0].Section);
        float lastCellY = rectLast.Y - rectFirst.Y;
        if (lastCellY > tableHeight - keyBoardHeight)
        {
            float diff = lastCellY - (tableHeight - tableMargin - keyBoardHeight);
            this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
        }

        float cellPosition = this._tableView.RectForSection(this._section).Y;
        if (cellPosition > tableHeight - keyBoardHeight)
        {
            if (this._tableView.ContentInset.Bottom == 0.0f)
            {
                float diff = cellPosition - (tableHeight - tableMargin - keyBoardHeight);
                this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
            }
            else
            {
                this._tableView.ScrollToRow(NSIndexPath.FromItemSection(0, this._section), UITableViewScrollPosition.Middle, true);
            }
        }
    }

    partial void EditingEnd(UITextField sender)
    {
        UIView.BeginAnimations(null);
        UIView.SetAnimationDuration(0.3f);
        this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, 0.0f, 0.0f);
        UIView.CommitAnimations();
    }

そして、あなたのView Controllerクラスで:

    public override void WillAnimateRotation(UIInterfaceOrientation toInterfaceOrientation, double duration)
    {
        base.WillAnimateRotation(toInterfaceOrientation, duration);

        float bottom = this.TableView.ContentInset.Bottom;
        if (bottom > 0.0f)
        {
            if (toInterfaceOrientation == UIInterfaceOrientation.Portrait || toInterfaceOrientation == UIInterfaceOrientation.PortraitUpsideDown)
            {
                bottom = bottom * UIScreen.MainScreen.Bounds.Width / UIScreen.MainScreen.Bounds.Height;
            }
            else
            {
                bottom = bottom * UIScreen.MainScreen.Bounds.Height / UIScreen.MainScreen.Bounds.Width;
            }

            UIEdgeInsets insets = this.TableView.ContentInset;
            this.TableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, bottom, 0.0f);
        }
    }  
1
U. Ali

UITableViewまたはUIScrollViewがある場合は、contentOffsetに変更を加える代わりに、frameの値を変更することをお勧めします。

Peter's Answer に取り組んで、このメソッドをクラスに追加するとうまくいきます:

- (void)textViewDidBeginEditing:(UITextField *)textField {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35f];
    CGPoint offset = self.tableView.contentOffset;
    offset.y += 200; // You can change this, but 200 doesn't create any problems
    [self.tableView setContentOffset:offset];
    [UIView commitAnimations];
}

それだけです。textViewDidEndEditingメソッドを追加する必要はありません。


これを言う必要はありませんが、これが機能するためにはUITextFieldまたはUITextViewがデリゲートである必要がありますコントローラーの。

0
Sheharyar

Peterの答えから始めて、iOS 10.1でSwift 3.0で次のアプローチを開発しました。textViewでこれを行っているので、ビューを調整するUITextViewDelegate関数textViewDidBeginEditingおよびtextViewDidEndEditingを実装しました。ご覧のとおり、Origin Yの値を小さな正の数に設定して上にスクロールし、0に戻って元の位置に戻ります。

ここに私のViewControllerからの関連するコードがあります。アニメートする必要はありませんが、素敵なタッチが追加されます。

func textViewDidBeginEditing(_ textView: UITextView)
{
    if UIScreen.main.bounds.height < 568 { 
        UIView.animate(withDuration: 0.75, animations: {
            self.view.bounds.Origin.y = 60
        })
    }
}

func textViewDidEndEditing(_ textView: UITextView)
{
    if UIScreen.main.bounds.height < 568 {
        UIView.animate(withDuration: 0.75, animations: {
            self.view.bounds.Origin.y = 0
        })
    }
}
0
Mario Hendricks