Edited at

[Swift] UITextFieldがキーボードに隠れないようにするやり方

More than 1 year has passed since last update.

[2017.02.09 Swift3.0に対応]

・ラベルの追加参考サイト

・println を printに変更

などなど


Xcodeのstoryboardを使用しないやり方です。

storyboardを使用して開発する方は、参考サイトが役立ちます。


はじめに

アプリ内でUITextFieldをタップすると下からニョキッとキーボードが出て来ます。

この時、UITextFieldがキーボードに隠れてしまい、

自分が何を入力しているのかが確認できなくなってしまうため、その解決方法を載せます。

ソースコードだけ見たい方は、一番下に完成コードを載せているので、そちらをどうぞ。


解決方法

UIScrollViewを使用します。

TextFieldの下辺とキーボードの上辺が重なったら、ScrollViewで指定した長さずらしてあげます。

そうすれば、TextFeildはキーボードに隠れません。


実装

それでは、以下の順に実装していきましょう。


1. プロジェクトの作成

今回はUITextFieldとUIScrollViewしか使用しないため、

Single View Applicationを選択してプロジェクトを作成します。


2. UITextFeild


2-1. UITextfieldの追加

text1text2の2つのUITextFieldを追加する。


ViewController.swift


class ViewController: UIViewController {
let text1: UITextField = UITextField(frame: CGRect(x: 0,y: 0,width: 200,height: 30))
let text2: UITextField = UITextField(frame: CGRect(x: 0,y: 0,width: 200,height: 30))

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

// 表示する文字を代入する.
text1.text = ""
text2.text = ""

// 枠を表示する.
text1.borderStyle = UITextBorderStyle.RoundedRect
text2.borderStyle = UITextBorderStyle.RoundedRect

// UITextFieldの表示する位置を設定する.
text1.layer.position = CGPoint(x:self.view.bounds.width/2,y:500);
text2.layer.position = CGPoint(x:self.view.bounds.width/2,y:100);

self.view.addSubview(text1)
self.view.addSubview(text2)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}


これで実行すると下記のようになる。

text1が一番下でtext2が一番上のTextFieldです。

実行結果1.png

もし、text1とtext2のTextFieldを押してもキーボードが出てこない場合、Xcodeの設定を確認してみましょう。参考サイト

これだけだと、

TextFieldのキーボードのEnterを押してもキーボードが閉じません


2-2. Enterを押したらキーボードが閉じるようにする

下記の関数をViewController.swift内に追加する

    //改行ボタンが押された際に呼ばれる.

func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()

return true
}

これで、TextFieldのキーボードのEnterを押したらキーボードが閉じるようになりました。


3. UIScrollView

このままだとtext1がキーボードに隠れているため、UIScrollViewで隠れないようにします。


3-1 UIScrollViewの追加

UIScrollViewを使用するために必要な処理を書いていきます。

以下が追加された後のViewController.swiftです。


ViewController.swift

import UIKit

class ViewController: UIViewController, UITextFieldDelegate, UIScrollViewDelegate{
let text1: UITextField = UITextField(frame: CGRectMake(0,0,200,30))
let text2: UITextField = UITextField(frame: CGRectMake(0,0,200,30))
let sc = UIScrollView();

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

sc.frame = self.view.frame;
sc.backgroundColor = UIColor.red;
sc.delegate = self;

//textfileの位置を指定する
sc.contentSize = CGSize(width: 250,height: 1000)
self.view.addSubview(sc);

// 表示する文字を代入する.
text1.text = ""
text2.text = ""

// Delegateを設定する.
text1.delegate = self
text2.delegate = self

// 枠を表示する.
text1.borderStyle = UITextBorderStyle.roundedRect
text2.borderStyle = UITextBorderStyle.roundedRect

// UITextFieldの表示する位置を設定する.
text1.layer.position = CGPoint(x:self.view.bounds.width/2,y:500);
text2.layer.position = CGPoint(x:self.view.bounds.width/2,y:100);

self.view.addSubview(text1)
self.view.addSubview(text2)

// Viewに追加する
sc.addSubview(text1)
sc.addSubview(text2)

}

//改行ボタンが押された際に呼ばれる.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()

return true
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}


UIScrollViewの範囲を確認できるように、

sc.backgroundColor = UIColor.redColor();

を追加したため、背景が赤色になっています。


4. TextFieldを上にスクロールさせる処理

ここから、TextFieldとキーボードが重なったときにスクロールさせる処理を書いていきます。


4.1 UITextFieldの情報を格納する

UITextFieldの情報を格納するための変数を定義します。

var txtActiveField = UITextField()

text1またはtext2のUITextFieldが押されたとき、

その情報をtxtActiveFieldへ格納するための関数を以下に示します。

//UITextFieldが編集された直後に呼ばれる.

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {

txtActiveField = textField
return true
}


4.2 UITextFieldの下辺とキーボードの上辺が重なっているかどうか調べるための処理

override func viewWillAppear(_ animated: Bool) {

super.viewWillAppear(animated)

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(ViewController.handleKeyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
notificationCenter.addObserver(self, selector: #selector(ViewController.handleKeyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}

func handleKeyboardWillShowNotification(_ notification: Notification) {

let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let myBoundSize: CGSize = UIScreen.main.bounds.size

var txtLimit = txtActiveField.frame.origin.y + txtActiveField.frame.height + 8.0
let kbdLimit = myBoundSize.height - keyboardScreenEndFrame.size.height

print("テキストフィールドの下辺:(\(txtLimit))")
print("キーボードの上辺:(\(kbdLimit))")

if txtLimit >= kbdLimit {
sc.contentOffset.y = txtLimit - kbdLimit
}
}

func handleKeyboardWillHideNotification(_ notification: Notification) {

sc.contentOffset.y = 0
}


4.3 スクロールする領域を知りたい場合は下記の関数を書けばLogで確認することが出来ます。

func scrollViewDidScroll(scrollView: UIScrollView)

{
// scroll領域取得
NSLog("%f %f", scrollView.contentOffset.x,scrollView.contentOffset.y);
}


完成版ソースコード

完成したプログラムを以下に示します。

新しく作ったプロジェクトのViewController.swiftファイルを

以下のコードに書き換えるだけで、

UITextFieldがキーボードに隠れないようにするやり方を確認することが出来ます。


ViewController.swift

import UIKit

class ViewController: UIViewController, UITextFieldDelegate, UIScrollViewDelegate{
let text1: UITextField = UITextField(frame: CGRect(x: 0,y: 0,width: 200,height: 30))
let text2: UITextField = UITextField(frame: CGRect(x: 0,y: 0,width: 200,height: 30))
let sc = UIScrollView();
var txtActiveField = UITextField()

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

sc.frame = self.view.frame;
sc.backgroundColor = UIColor.red;
sc.delegate = self;

//textfileの位置を指定する
sc.contentSize = CGSize(width: 250,height: 1000)
self.view.addSubview(sc);

// 表示する文字を代入する.
text1.text = ""
text2.text = ""

// Delegateを設定する.
text1.delegate = self
text2.delegate = self

// 枠を表示する.
text1.borderStyle = UITextBorderStyle.roundedRect
text2.borderStyle = UITextBorderStyle.roundedRect

// UITextFieldの表示する位置を設定する.
text1.layer.position = CGPoint(x:self.view.bounds.width/2,y:500);
text2.layer.position = CGPoint(x:self.view.bounds.width/2,y:100);

self.view.addSubview(text1)
self.view.addSubview(text2)

// Viewに追加する
sc.addSubview(text1)
sc.addSubview(text2)

}

//改行ボタンが押された際に呼ばれる.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()

return true
}

//UITextFieldが編集された直後に呼ばれる.
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
txtActiveField = textField
return true
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(ViewController.handleKeyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
notificationCenter.addObserver(self, selector: #selector(ViewController.handleKeyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func handleKeyboardWillShowNotification(_ notification: Notification) {

let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let myBoundSize: CGSize = UIScreen.main.bounds.size
var txtLimit = txtActiveField.frame.origin.y + txtActiveField.frame.height + 8.0
let kbdLimit = myBoundSize.height - keyboardScreenEndFrame.size.height

print("テキストフィールドの下辺:(\(txtLimit))")
print("キーボードの上辺:(\(kbdLimit))")

if txtLimit >= kbdLimit {
sc.contentOffset.y = txtLimit - kbdLimit
}
}

func handleKeyboardWillHideNotification(_ notification: Notification) {
sc.contentOffset.y = 0
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}


ダウンロードしてそのまま実行させて確認したいって方は下からどうぞ。

https://github.com/chankei1/scroll_sample


参考サイト

「Swiftでテキストフィールドがキーボードに隠れないようにしてみた」

URL:http://ameblo.jp/hayashidesuga/entry-11971210696.html

「Xcode 6のiOS Simulatorでキーボードが表示されない場合の対処法」

URL:http://yutaihara.com/archives/147