IPhone用の入力画面を作成しようとしています。画面にはいくつかの入力フィールドがあります。それらのほとんどは画面の上部にありますが、2つのフィールドが下部にあります。ユーザーが画面下部のテキストを編集しようとすると、キーボードがポップアップして画面を覆います。これが発生したときに画面を上に移動する簡単な解決策を見つけましたが、結果として画面alwaysが上に移動し、画面上部のフィールドが手の届かない場所に移動します。ユーザーがそれらを編集しようとしたとき。
下部のフィールドが編集されたときに、画面をonlyに移動させる方法はありますか?
ここで見つけた このコードを使いました :
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(sender: NSNotification) {
self.view.frame.Origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
self.view.frame.Origin.y += 150
}
あなたの問題はAppleによるこの文書 でよく説明されています 。このページのコード例(Listing 4-1
)はまさにあなたが必要とすることをします、それは現在の編集がキーボードの下にあるべきであるときだけあなたの見解をスクロールするでしょう。必要なコントロールをscrollViiewに配置するだけです。唯一の問題は、これがObjective-Cであるということです。Swiftではそれが必要だと思います。
変数を宣言する
var activeField: UITextField?
それからこれらのメソッドを追加します
func registerForKeyboardNotifications()
{
//Adding notifies on keyboard appearing
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
}
func deregisterFromKeyboardNotifications()
{
//Removing notifies on keyboard appearing
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWasShown(notification: NSNotification)
{
//Need to calculate keyboard exact size due to Apple suggestions
self.scrollView.scrollEnabled = true
var info : NSDictionary = notification.userInfo!
var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeFieldPresent = activeField
{
if (!CGRectContainsPoint(aRect, activeField!.frame.Origin))
{
self.scrollView.scrollRectToVisible(activeField!.frame, animated: true)
}
}
}
func keyboardWillBeHidden(notification: NSNotification)
{
//Once keyboard disappears, restore original positions
var info : NSDictionary = notification.userInfo!
var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.view.endEditing(true)
self.scrollView.scrollEnabled = false
}
func textFieldDidBeginEditing(textField: UITextField!)
{
activeField = textField
}
func textFieldDidEndEditing(textField: UITextField!)
{
activeField = nil
}
必ずViewControllerをUITextFieldDelegate
として宣言し、初期化メソッドに正しいデリゲートを設定してください。
self.you_text_field.delegate = self
また、viewInitでregisterForKeyboardNotifications
を、終了時にderegisterFromKeyboardNotifications
を呼び出すことを忘れないでください。
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)
}
func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWasShown(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeField = self.activeField {
if (!aRect.contains(activeField.frame.Origin)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}
@objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.view.endEditing(true)
self.scrollView.isScrollEnabled = false
}
func textFieldDidBeginEditing(_ textField: UITextField){
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField){
activeField = nil
}
これが私の2セントです。
試してみましたか: https://github.com/hackiftekhar/IQKeyboardManager
SwiftやObjective-Cをインストールするのは非常に簡単です。
これがどのように動作するのか
IQKeyboardManager(Swift): - IQKeyboardManagerSwiftはCocoaPodsから入手できます。インストールするには、単にPodfileに次の行を追加します。
pod 'IQKeyboardManagerSwift'
AppDelegate.Swiftで、IQKeyboardManagerSwiftフレームワークをインポートしてIQKeyboardManagerを有効にするだけです。
import IQKeyboardManagerSwift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
IQKeyboardManager.sharedManager().enable = true
// For Swift 4, use this instead
// IQKeyboardManager.shared.enable = true
return true
}
}
そしてそれがすべてです。簡単です!
私が私のために完璧に働くことがわかったのはこれです:
func textFieldDidBeginEditing(textField: UITextField) {
if textField == email || textField == password {
animateViewMoving(true, moveValue: 100)
}
}
func textFieldDidEndEditing(textField: UITextField) {
if textField == email || textField == password {
animateViewMoving(false, moveValue: 100)
}
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:NSTimeInterval = 0.3
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations("animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
高さの値も変更できます。すべてのテキストフィールドに使用する場合は、 "ifステートメント"を削除してください。
TextViewのようにユーザー入力を必要とするすべてのコントロールにこれを使用することさえできます。
のみ下部のフィールドが編集されたときに画面を移動する方法はありますか?
同様の問題があり、scrollViewを使用し、代わりにkeyboardWillShow/Hideメソッド内のifステートメントを使用して、かなり簡単な解決策を見つけましたwithout。
func keyboardWillShow(notification: NSNotification) {
if bottomText.editing{
self.view.window?.frame.Origin.y = -1 * getKeyboardHeight(notification)
}
}
func keyboardWillHide(notification: NSNotification) {
if self.view.window?.frame.Origin.y != 0 {
self.view.window?.frame.Origin.y += getKeyboardHeight(notification)
}
}
テキストフィールドが2つしかなかったので、これは私にとって良い解決策でした。
ビュー全体を上にシフト:特定のテキストフィールド(bottomText)が編集された場合のみ
ビュー全体を下にシフト:ビューが元の場所にない場合のみ
代わりにこれをUITableViewControllerに実装しないでください。キーボードは、表示されてもテキストフィールドを非表示にしません。
キーボードが表示されたら、この拡張子を使ってUIViewを移動してください。
extension UIView {
func bindToKeyboard(){
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChange(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
@objc func keyboardWillChange(_ notification: NSNotification){
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let beginningFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = endFrame.Origin.y - beginningFrame.Origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.frame.Origin.y += deltaY
}, completion: nil)
}
}
次にあなたのviewdidloadであなたのビューをキーボードにバインドします
UiView.bindToKeyboard()
Swift 4(**を更新)と拡張子**
inViewDidLoad
self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain
self.watchForKeyboard()
次の拡張子を追加
import UIKit
private var xoAssociationKeyForBottomConstrainInVC: UInt8 = 0
extension UIViewController {
var containerDependOnKeyboardBottomConstrain :NSLayoutConstraint! {
get {
return objc_getAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC) as? NSLayoutConstraint
}
set(newValue) {
objc_setAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
func watchForKeyboard() {
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown(notification:)), name:UIResponder.keyboardWillShowNotification, object: nil);
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name:UIResponder.keyboardWillHideNotification, object: nil);
}
@objc func keyboardWasShown(notification: NSNotification) {
let info = notification.userInfo!
let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.containerDependOnKeyboardBottomConstrain.constant = -keyboardFrame.height
self.view.layoutIfNeeded()
})
}
@objc func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.containerDependOnKeyboardBottomConstrain.constant = 0
self.view.layoutIfNeeded()
})
}
}
私はSwiftLintを使用していますが、これには受け入れられた回答のフォーマットに関するいくつかの問題がありました。具体的には:
コロンの前にスペースを空けず、強制的にキャストしても、UIEdgeInsetMakeの代わりにUIEdgeInset(top:etc ...)を使用.
だからここにSwift 3のためのそれらの更新があります
func registerForKeyboardNotifications() {
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func deregisterFromKeyboardNotifications() {
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWasShown(notification: NSNotification) {
//Need to calculate keyboard exact size due to Apple suggestions
scrollView?.isScrollEnabled = true
var info = notification.userInfo!
if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)
scrollView?.contentInset = contentInsets
scrollView?.scrollIndicatorInsets = contentInsets
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
if let activeField = self.activeField {
if !aRect.contains(activeField.frame.Origin) {
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}
}
func keyboardWillBeHidden(notification: NSNotification) {
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize.height, right: 0.0)
scrollView?.contentInset = contentInsets
scrollView?.scrollIndicatorInsets = contentInsets
}
view.endEditing(true)
scrollView?.isScrollEnabled = false
}
func textFieldDidBeginEditing(_ textField: UITextField) {
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
activeField = nil
}
私はこの条項は間違っていると思います。
if (!CGRectContainsPoint(aRect, activeField!.frame.Origin))
ActiveFieldのOriginはキーボードより上にあるかもしれませんが、maxYはそうではないかもしれません...
私はactiveFieldの '最大'ポイントを作成し、それがキーボードRectにあるかどうかをチェックします。
swift 4.2の場合.
これはどのフォームにも当てはまります。スクロールビューは必要ありません。デリゲートを設定することを忘れないでください。
Uitextfieldのvarを作る
var clickedTextField = UITextField()
あなたのviewdid負荷に
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
クリックされたテキストフィールドを知ってください。おそらく画面全体にテキストフィールドがあります。
func textFieldDidBeginEditing(_ textField: UITextField) {
clickedTextField = textField
}
キーボードがテキストフィールドを覆っているかどうかを確認してください。
@objc func keyboardWillShow(sender: NSNotification,_ textField : UITextField) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if clickedTextField.frame.Origin.y > keyboardSize.Origin.y {
self.view.frame.Origin.y = keyboardSize.Origin.y - clickedTextField.center.y - 20
}
}
}
@objc func keyboardWillHide(sender: NSNotification) {
self.view.frame.Origin.y = 0
}
閉じるキーボードに戻る
func textFieldShouldReturn(_ textField: UITextField) -> Bool { //delegate method
textField.resignFirstResponder()
return true
}
更新:NSNotification.Name.UIKeyboardWillShowとNSNotification.Name.UIKeyboardWillHideは、それぞれUIResponder.keyboardWillShowNotificationとUIResponder.keyboardWillHideNotificationに変更されました。
素晴らしい答えはすでに与えられていますが、これはこの状況に対処するための別の方法です(Swift 3xを使用)。
まずviewWillAppear()
で以下のメソッドを呼び出します
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillBeHidden), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
これでIBOutlet
のUIView
の上の制約のうちのUIViewcontroller
を次のように1つ取ります。(ここでUIView
はUIScrollView
のサブビューです。つまり、すべてのUIScrollView
に対してsubViews
が必要です)
@IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!
そして、次のような別の変数にデリゲートを追加します。すなわちUITextFieldDelegate
:
var activeTextField = UITextField() //This is to keep the reference of UITextField currently active
その後、ここに魔法の部分がありますスニペットを貼り付けるだけです。
func keyboardWasShown(_ notification: Notification) {
let keyboardInfo = notification.userInfo as NSDictionary?
//print(keyboardInfo!)
let keyboardFrameEnd: NSValue? = (keyboardInfo?.value(forKey: UIKeyboardFrameEndUserInfoKey) as? NSValue)
let keyboardFrameEndRect: CGRect? = keyboardFrameEnd?.cgRectValue
if activeTextField.frame.Origin.y + activeTextField.frame.size.height + 10 > (keyboardFrameEndRect?.Origin.y)! {
UIView.animate(withDuration: 0.3, delay: 0, options: .transitionFlipFromTop, animations: {() -> Void in
//code with animation
//Print some stuff to know what is actually happening
//print(self.activeTextField.frame.Origin.y)
//print(self.activeTextField.frame.size.height)
//print(self.activeTextField.frame.size.height)
self.loginViewTopConstraint.constant = -(self.activeTextField.frame.Origin.y + self.activeTextField.frame.size.height - (keyboardFrameEndRect?.Origin.y)!) - 30.0
self.view.layoutIfNeeded()
}, completion: {(_ finished: Bool) -> Void in
//code for completion
})
}
}
func keyboardWillBeHidden(_ notification: Notification) {
UIView.animate(withDuration: 0.3, animations: {() -> Void in
self.loginViewTopConstraint.constant = self.view.frame.Origin.y
self.view.layoutIfNeeded()
})
}
//MARK: textfield delegates
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
activeTextField = textField
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
switch textField {
case YOUR_TEXTFIELD_ONE:
YOUR_TEXTFIELD_TWO.becomeFirstResponder()
break
case YOUR_TEXTFIELD_TWO:
YOUR_TEXTFIELD_THREE.becomeFirstResponder()
break
default:
textField.resignFirstResponder()
break
}
return true
}
最後のスニペット:
//Remove Keyboard Observers
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
UITextField
内のすべてのUIStoryboard
に代議員を割り当てることを忘れないでください
がんばろう!
Swift 3の構文:
func textFieldDidBeginEditing(_ textField: UITextField) {
// add if for some desired textfields
animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(_ textField: UITextField) {
// add if for some desired textfields
animateViewMoving(up: false, moveValue: 100)
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
textFieldDidEndEditing(_ textField: UITextField) {
let movementDuration:TimeInterval = 0.5
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations("animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
これは、特定のテキストフィールドに「if」条件を追加できるようにしたいものを取得するためのいい方法です。
まず最初に、あなたのアクティブなUITextFieldを識別するための変数を宣言します。
ステップ1:-
var activeTextField: UITextField
のように?
ステップ2: - この後、viewDidLoadにこれら2行を追加します。
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
ステップ3: -
今すぐあなたのコントローラクラスでこれら二つのメソッドを定義してください。
func keyboardWillShow(_ notification: NSNotification) {
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeField = self.activeField {
if (!aRect.contains(activeField.frame.Origin)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}
func keyboardWillHide(_ notification: NSNotification) {
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.view.endEditing(true)
self.scrollView.isScrollEnabled = true
}
func textFieldDidBeginEditing(_ textField: UITextField){
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField){
activeField = nil
}
以下の例では、txtLastNameまたはtxtCityの編集を開始したときにのみビューを上に移動しています。 txtLastNameをクリックした後、そのtxtCityの後にビューを2倍上に移動できるため、変数keyboardActiveを作成しました。
見て、それがあなたのために働くかどうか確かめてください。
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var txtFirstName: UITextField!
@IBOutlet weak var txtLastName: UITextField!
@IBOutlet weak var txtCity: UITextField!
var keyboardActive = false
override func viewDidLoad() {
super.viewDidLoad()
self.txtFirstName.delegate = self
self.txtLastName.delegate = self
self.txtCity.delegate = self
}
func textFieldDidBeginEditing(textField: UITextField) {
if textField != self.txtFirstName && keyboardActive == false {
self.view.frame.Origin.y -= 165
self.keyboardActive = true
}
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
if textField != self.txtFirstName && keyboardActive == true {
self.view.frame.Origin.y += 165
self.keyboardActive = false
}
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
}
これは、Appleが提供しているドキュメントと以前の投稿を読んだ後の私のバージョンです。私が気づいたことの一つは、textViewがキーボードで覆われていると扱われなかったことです。残念なことに、なんらかの理由でtextViewDidBeginEditingが呼び出された後にキーボードが呼び出されるため、Appleのドキュメントは機能しません。私はキーボードが表示されているかどうか、そしてtextViewかtextFieldが編集されているかどうかをチェックする中心的なメソッドを呼び出すことによってこれを処理しました。この方法では、プロセスは両方の条件が存在する場合にのみ起動されます。
TextViewsのもう1つのポイントは、それらの高さがキーボードがtextViewの下部を固定し、の左上の点が表示されている場合には調整されないということです。したがって、私が書いたコードは実際にはtextViewまたはtextFieldの画面参照の左下の点を取り、それが提示されたキーボードの画面参照の座標内にあるかどうかを調べ、キーボードがその一部を覆うことを意味します。
let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil)
if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.Origin.x, aRect.maxY))) {
// scroll textView/textField into view
}
ナビゲーションコントローラを使用している場合、サブクラスはインセットのスクロールビューの自動調整もfalseに設定します。
self.automaticallyAdjustsScrollViewInsets = false
処理のためにデリゲートを設定するために、それぞれのtextViewとtextFieldを調べます。
for view in self.view.subviews {
if view is UITextView {
let tv = view as! UITextView
tv.delegate = self
} else if view is UITextField {
let tf = view as! UITextField
tf.delegate = self
}
}
結果を得るために、基本クラスをここで作成したサブクラスに設定するだけです。
import UIKit
class ScrollingFormViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate {
var activeFieldRect: CGRect?
var keyboardRect: CGRect?
var scrollView: UIScrollView!
override func viewDidLoad() {
self.automaticallyAdjustsScrollViewInsets = false
super.viewDidLoad()
// Do any additional setup after loading the view.
self.registerForKeyboardNotifications()
for view in self.view.subviews {
if view is UITextView {
let tv = view as! UITextView
tv.delegate = self
} else if view is UITextField {
let tf = view as! UITextField
tf.delegate = self
}
}
scrollView = UIScrollView(frame: self.view.frame)
scrollView.scrollEnabled = false
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.addSubview(self.view)
self.view = scrollView
}
override func viewDidLayoutSubviews() {
scrollView.sizeToFit()
scrollView.contentSize = scrollView.frame.size
super.viewDidLayoutSubviews()
}
deinit {
self.deregisterFromKeyboardNotifications()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func registerForKeyboardNotifications()
{
//Adding notifies on keyboard appearing
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWasShown), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWillBeHidden), name: UIKeyboardWillHideNotification, object: nil)
}
func deregisterFromKeyboardNotifications()
{
//Removing notifies on keyboard appearing
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWasShown(notification: NSNotification)
{
let info : NSDictionary = notification.userInfo!
keyboardRect = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
adjustForKeyboard()
}
func keyboardWillBeHidden(notification: NSNotification)
{
keyboardRect = nil
adjustForKeyboard()
}
func adjustForKeyboard() {
if keyboardRect != nil && activeFieldRect != nil {
let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil)
if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.Origin.x, aRect.maxY)))
{
scrollView.scrollEnabled = true
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardRect!.size.height, 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
scrollView.scrollRectToVisible(activeFieldRect!, animated: true)
}
} else {
let contentInsets : UIEdgeInsets = UIEdgeInsetsZero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
scrollView.scrollEnabled = false
}
}
func textViewDidBeginEditing(textView: UITextView) {
activeFieldRect = textView.frame
adjustForKeyboard()
}
func textViewDidEndEditing(textView: UITextView) {
activeFieldRect = nil
adjustForKeyboard()
}
func textFieldDidBeginEditing(textField: UITextField)
{
activeFieldRect = textField.frame
adjustForKeyboard()
}
func textFieldDidEndEditing(textField: UITextField)
{
activeFieldRect = nil
adjustForKeyboard()
}
}
Swift 4.2
私の解決策は、その位置がキーボードの下にある場合、(垂直に)ビューをUITextField
の中央に配置します。
ステップ1:新しいSwiftファイルを作成してUIViewWithKeyboard
クラスをコピーアンドペーストします。
ステップ2:Interface Builderで、一番上のUIView
のカスタムクラスとして設定します。
import UIKit
class UIViewWithKeyboard: UIView {
@IBInspectable var offsetMultiplier: CGFloat = 0.75
private var keyboardHeight = 0 as CGFloat
private weak var activeTextField: UITextField?
override func awakeFromNib() {
super.awakeFromNib()
NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.textDidBeginEditing),
name: UITextField.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillShow),
name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillHide),
name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func textDidBeginEditing(_ notification: NSNotification) {
self.activeTextField = notification.object as? UITextField
}
@objc func keyboardWillShow(_ notification: Notification) {
if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
keyboardHeight = frameValue.cgRectValue.size.height
if let textField = self.activeTextField {
let offset = textField.frame.maxY < frame.maxY - keyboardHeight ? 0
: textField.frame.maxY - (frame.maxY - keyboardHeight) * offsetMultiplier
self.setView(offset: offset)
}
}
}
@objc func keyboardWillHide(_ notification: NSNotification) {
self.setView(offset: 0)
}
func setView(offset: CGFloat) {
UIView.animate(withDuration: 0.25) {
self.bounds.Origin.y = offset
}
}
}
スイフト3
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var edtEmail: UITextField!
@IBOutlet var bottomTextfieldConstrain: NSLayoutConstraint! // <- this guy is the constrain that connect the bottom of textField to lower object or bottom of page!
@IBAction func edtEmailEditingDidBegin(_ sender: Any) {
self.bottomTextfieldConstrain.constant = 200
let point = CGPoint(x: 0, y: 200)
scrollView.contentOffset = point
}
@IBAction func edtEmailEditingDidEnd(_ sender: Any) {
self.bottomTextfieldConstrain.constant = 50
}
受け入れられているanwserはほぼ完璧です。しかし、私はUIKeyboardFrameBeginUserInfoKey,
の代わりにUIKeyboardFrameEndUserInfoKey
を使う必要があります。後者はkeyboradの高さ0を返すからです。そしてヒットテストポイントをOriginではなく一番下に変更します。
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeField = self.activeField {
var point = activeField.frame.Origin
point.y += activeField.frame.size.height
if (!aRect.contains(point)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
スイフト4
アニメーション付きキーボードでUITextField
を簡単に上下に動かすことができます
import UIKit
class ViewController: UIViewController {
@IBOutlet var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
textField.resignFirstResponder()
}
@objc func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.Origin.y - curFrame.Origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.textField.frame.Origin.y+=deltaY
},completion: nil)
}
Swift 4私の解決策を更新しました
キーボードの表示/非表示のコンストレインアニメーションで、お楽しみください。
import Foundation
import UIKit
class PhoneController: UIViewController, UITextFieldDelegate{
var phoneLayoutYConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
phoneField.delegate = self
view.addSubview(phoneField)
NSLayoutConstraint.activate([phoneField.heightAnchor.constraint(equalToConstant: 50),
phoneField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
phoneField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
phoneField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)])
phoneLayoutYConstraint = NSLayoutConstraint(item: phoneField, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
phoneLayoutYConstraint?.isActive = true
}
let phoneField: UITextField = {
let text = UITextField()
text.translatesAutoresizingMaskIntoConstraints = false
text.keyboardType = .numberPad
text.font = UIFont.systemFont(ofSize: 30)
text.layer.cornerRadius = 5.0
text.layer.masksToBounds = true
text.layer.borderColor = UIColor.darkGray.cgColor
text.layer.borderWidth = 2.0
return text
}()
override func viewDidDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
func textFieldDidBeginEditing(_ textField: UITextField) {
}
func textFieldDidEndEditing(_ textField: UITextField) {
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
@objc func handleKeyBoardNotification(_ notification: NSNotification) {
if let info = notification.userInfo {
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let isKeyBoardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
var aRect : CGRect = self.phoneField.frame
aRect.size.height -= keyboardSize!.height
phoneLayoutYConstraint?.constant = isKeyBoardShowing ? -keyboardSize!.height : 0
UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (boo) in
})
}
}
}
Swift 4.2用に書き直されました
ViewDidLoad ..では.
NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWasShown), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWillBeHidden), name: UIResponder.keyboardWillHideNotification, object: nil)
残りの機能
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWasShown(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
aRect.size.height -= keyboardSize!.height
if let activeField = self.activeField {
if (!aRect.contains(activeField.frame.Origin)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}
@objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.view.endEditing(true)
self.scrollView.isScrollEnabled = false
}
func textFieldDidBeginEditing(_ textField: UITextField){
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField){
activeField = nil
}
Swift 4.2の場合
このコードにより、特定のデバイス画面サイズに対してフレームのY軸モーメントを制御できます。
シモンズ:このコードは、TextFieldの位置に基づいてフレームをインテリジェントに移動しません。
UIDevice用の拡張子を作成します
extension UIDevice {
enum ScreenType: String {
case iPhone4_4S = "iPhone 4 or iPhone 4s"
case iPhones_5_5s_5c_SE = "iPhone 5, iPhone 5s, iPhone 5c or iPhone SE"
case iPhones_6_6s_7_8 = "iPhone 6, iPhone 6s, iPhone 7 or iPhone 8"
case iPhones_6Plus_6sPlus_7Plus_8Plus = "iPhone 6 Plus, iPhone 6s Plus, iPhone 7 Plus or iPhone 8 Plus"
case iPhoneX_Xs = "iPhone X, iPhone Xs"
case iPhoneXR = "iPhone XR"
case iPhoneXSMax = "iPhone Xs Max"
case unknown
}
var screenType: ScreenType {
switch UIScreen.main.nativeBounds.height {
case 960:
return .iPhone4_4S
case 1136:
return .iPhones_5_5s_5c_SE
case 1334:
return .iPhones_6_6s_7_8
case 1920, 2208:
return .iPhones_6Plus_6sPlus_7Plus_8Plus
case 1792:
return .iPhoneXR
case 2436:
return .iPhoneX_Xs
case 2688:
return .iPhoneXSMax
default:
return .unknown
}
}
}
viewDidLoadにNotificationObserverを追加します
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
セレクタ
@objc func keyboardWillShow(notification: NSNotification) {
if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
if self.view.frame.Origin.y == 0 {
switch (UIDevice.current.screenType.rawValue) {
case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
self.view.frame.Origin.y -= 210
case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
self.view.frame.Origin.y -= 110
case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
self.view.frame.Origin.y -= 80
case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
self.view.frame.Origin.y -= 70
case (UIDevice.ScreenType.iPhoneXR.rawValue):
self.view.frame.Origin.y -= 70
case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
self.view.frame.Origin.y -= 70
default:
self.view.frame.Origin.y -= 150
}
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
if self.view.frame.Origin.y != 0 {
switch (UIDevice.current.screenType.rawValue) {
case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
self.view.frame.Origin.y += 210
case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
self.view.frame.Origin.y += 110
case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
self.view.frame.Origin.y += 80
case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
self.view.frame.Origin.y += 70
case (UIDevice.ScreenType.iPhoneXR.rawValue):
self.view.frame.Origin.y += 70
case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
self.view.frame.Origin.y += 70
default:
self.view.frame.Origin.y += 150
}
}
}
}
「Swiftの初心者であることを忘れていました。(これをチェックするための正しい構文は何ですか?(この関数でフィールド名を取得する方法は?)」
OK 。最初にUITextFieldDelegateプロトコルを確認してください
class YourClass:UITextFieldDelegate
それから機能を実行しなさい
func textFieldDidBeginEditing(textField: UITextField!) {
if textField == txtOne
{
println("TextOne")
}
if textField == txtTwo
{
println("TextTwo")
}
}
あなたは適切なアプローチはスクロールビューを使用してスクロールビューの内側に上下に移動させるべきビューを配置し、それに応じてキーボードイベントを処理することです。
このコードでは、編集中のテキストフィールドを上に移動するので、この回答のためにSwift 3で表示できるように、ビューをUITextFieldDelegateにする必要があります。
var moveValue: CGFloat!
var moved: Bool = false
var activeTextField = UITextField()
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeTextField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
if moved == true{
self.animateViewMoving(up: false, moveValue: moveValue )
moved = false
}
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:TimeInterval = 0.3
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations("animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
そしてviewDidLoadでは:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
どのview(viewDidLoadの外側):
func keyboardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardHeight = keyboardSize.height
if (view.frame.size.height-self.activeTextField.frame.Origin.y) - self.activeTextField.frame.size.height < keyboardHeight{
moveValue = keyboardHeight - ((view.frame.size.height-self.activeTextField.frame.Origin.y) - self.activeTextField.frame.size.height)
self.animateViewMoving(up: true, moveValue: moveValue )
moved = true
}
}
}