質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • Swift

    7435questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4075questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

全てのTextFieldが空の時を判別したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,267

tarofess

score 115

現在tableviewに複数のtextfieldがあり、全てのtextfieldが空の時は画面右上のbarbuttonitemをタップ不可にし、どれかに文字が1文字でも入るとbarbuttonitemをタップ可能にしたいのですが、以下のようにしてもうまくいきません。2文字目を入力した段階でbarbuttonitemがタップ可能になりますし、文字を全て消してもbarbuttonitemはタップ可能で、次に1文字入力するとbarbuttonitemがタップ不可能になるというように1アクション遅れます。

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let filledTextFieldCells = self.tableView.visibleCells.filter {
            if let cell = $0 as? Checkable {
                return cell.isFilledTextField()
            } else {
                return false
            }
        }
        if filledTextFieldCells.count == 0 {
            self.navigationItem.rightBarButtonItem?.isEnabled = false
        } else {
            self.navigationItem.rightBarButtonItem?.isEnabled = true
        }

        return true
    }

class NameEditTableViewCell: UITableViewCell, Checkable {

    @IBOutlet weak var nameTextField: UITextField!

    func isFilledTextField() -> Bool {
        return !self.nameTextField.text!.isEmpty ? true : false
    }

}


どうすれば入力と同時にtextfieldが空なのかどうかを判別することができるでしょうか?
どなたかわかる方がいれば教えていただきたいです。よろしくお願いします。

///回答を受けての追記///

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let newText = (textField.text as! NSString).replacingCharacters(in: range, with: string)

        let filledTextFieldCells = self.tableView.visibleCells.filter {
            if let cell = $0 as? Checkable {
                return cell.isFilledTextField(text: newText)
            } else {
                return false
            }
        }
        if filledTextFieldCells.count == 0 {
            self.navigationItem.rightBarButtonItem?.isEnabled = false
        } else {
            self.navigationItem.rightBarButtonItem?.isEnabled = true
        }

        return true
    }

extension Checkable {
    func isFilledTextField(text: String) -> Bool {
        return !text.isEmpty ? true : false
    }
}

///notificationを使ったやり方に変更///

func didChangeNotification(notification: Notification) {
        var noEmptyTextField = true

        if let textField = notification.object as? UITextField {
            switch textField.tag {
            case CellTag.name.rawValue:
                if let text = textField.text, !text.isEmpty {
                    noEmptyTextField = true
                } else {
                    noEmptyTextField = false
                }
            case CellTag.category.rawValue:
                if let text = textField.text, !text.isEmpty {
                    noEmptyTextField = true
                } else {
                    noEmptyTextField = false
                }
            case CellTag.price.rawValue:
                if let text = textField.text, !text.isEmpty {
                    noEmptyTextField = true
                } else {
                    noEmptyTextField = false
                }
            default:
                break
            }
        }

        if noEmptyTextField {
            self.navigationItem.rightBarButtonItem?.isEnabled = true
        } else {
            self.navigationItem.rightBarButtonItem?.isEnabled = false
        }
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2017/01/13 08:43 編集

    (deleted)

    キャンセル

回答 2

checkベストアンサー

+2

以下のように記述することで判定できると思います、参考にしてみてください。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var barButtonItem: UIBarButtonItem!
    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var textField2: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        barButtonItem.isEnabled = false

        // 入力値が変更された時に呼ばれる通知を登録
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.didChangeNotification(notification:)),
            name: NSNotification.Name.UITextFieldTextDidChange,
            object: nil
        )
    }

    var isInputTextField1 = false
    var isInputTextField2 = false
    var isInputTextField3 = false

    // 入力値が変更された時に呼ばれるメソッド
    func didChangeNotification(notification: Notification) {

        if let textField = notification.object as? UITextField {
            if let text = textField.text {
                switch textField.tag {
                case CellTag.name.rawValue    : isInputTextField1 = text.isEmpty ? false : true
                case CellTag.category.rawValue: isInputTextField2 = text.isEmpty ? false : true
                case CellTag.price.rawValue   : isInputTextField3 = text.isEmpty ? false : true
                default: break
                }
            }
        }

        barButtonItem.isEnabled = isInputTextField1 || isInputTextField2 || isInputTextField3 ? true : false
    }

    // 通知の解除
    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true)
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/13 08:30

    ご回答ありがとうございます。なるほど、NotificationCenterでもtextfieldの変化をハンドルできるんですね。しかしtextfieldが画面に複数あって、今の所うまくいってないです...。

    キャンセル

  • 2017/01/13 09:06

    回答を変更しました、通知のオブジェクトにUITextFieldのインスタンスが付いてくるのでどのテキストフィールドかは判断できます。

    キャンセル

  • 2017/01/13 21:23

    どのtextfieldのインスタンスなのか判別することはできるようになりました。しかし一つのtextfieldが空になるとbarButtonItemのenableがfalseになってしまいます。。。すみません、お手数をおかけしますが質問に現在詰まっている箇所のコードを追記しましたので、ご教授いただきたいです。

    キャンセル

  • 2017/01/13 21:33

    仕様が分からないのですが、複数あるTextFieldのうち一つでも入力があればボタンを押せるようにしたいと言うことですか?

    キャンセル

  • 2017/01/13 21:38

    はい、 複数textfieldがあり、一つでも入力があればボタンを押せるようにしたいです。今、一つでも入力があればボタンを押せるようになっているのですが、例えば二つのtextfieldに文字が入力されていて、その状態で一つのtextfieldの文字を全て消すとボタンが押せなくなってしまっています。

    キャンセル

  • 2017/01/13 21:44

    そのViewControllerクラスに変数として宣言してあるUITextFieldですか?

    キャンセル

  • 2017/01/13 21:49

    ViewControllerにUITextFieldの変数は宣言しておらず、UITableViewCellのサブクラス内でtextfieldは宣言しています。

    キャンセル

  • 2017/01/13 22:19

    強引ではありますがこのパターンに当てはめた実装で回答を修正しました、試してみてください。

    キャンセル

  • 2017/01/13 22:33

    ご提示のコードで動かすと期待していた動作になりました!最後まで親切に回答してくださり、誠にありがとうございます。助かりましたmm

    キャンセル

0

1アクション遅れるのは、textField(_:shouldChangeCharactersIn:replacementString:)の仕様を理解していないからです。この関数が呼ばれた時点ではテキストフィールドは更新されていません。

変更箇所(range)と変更内容(string)が渡されますので、元のテキストに対して、

let newText = (textField.text as NSString).replacingCharacters(in: range, with: string)
//動作未確認(nilチェックなど全くしていません)

とすると、変更後の文字列を生成できます。

この辺りを考慮して作り直してみてはどうでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/13 08:44

    ご回答ありがとうございます。shouldChangeCharactersInが呼ばれた時点でtextfieldは更新されないのですね。なのでご提示のコードを参考に修正してみたのですが、textfieldのどれか一つが空になるとbarbuttonitemがfalseになってしまいます。コードを追記したのですが、どこがおかしいでしょうか?

    キャンセル

  • 2017/01/13 09:10

    回答しておいてアレですが、textField(_:shouldChangeCharactersIn:replacementString:)を使うのはあまり良くないようなので、_Kentarouさんの回答を参考にした方が良いと思います。

    参考URL
    http://blog.fenrir-inc.com/jp/2011/01/textfield-validation.html
    http://blog.niw.at/post/92806309874

    キャンセル

  • 2017/01/13 21:19

    リンクの記事を見ると確かにshouldChangeCharactersInは使わない方が良さそうですね......。
    notificationを使うことにします。ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    swift : textFieldが複数ある場合に、datepickerの定義の方法

    現在、iphoneアプリを作成しているswift初心者です。 日付の期間指定の部分をを作成していまして、 FromのtextFieldをタップすると、datepickerが表示さ

  • 解決済

    キーボードが閉じない

    Main.storybodrdにUITextFieldを配置しています。これにキーボードで文字を入力した後、キーボードを閉じたいのでTextFieldと接続しているクラスをプロトコ

  • 受付中

    SwiftでTextFieldの値を読み込む

    Swiftで、Textfieldに打ち込まれた値をString型で取得し、関数に打ち込みたいのですが、自分なりのやり方ではできませんでした。方法を具体的に教えてください。(一応、自

  • 受付中

    Swift2

    Textfieldに入力された文字をTextfieldをタッチした時に消したいです 1回目Textfieldに入力する 2回目Textfieldに1回目に入力した物が残って

  • 解決済

    Swift3でボタンをタップした時にPickerViewをしたから出す方法

    前提・実現したいこと タイトル通りなのですが、ボタンをタップした時にピッカーが下から出てくるようにしたいです。 TextFieldをタップした時にピッカーが下から出るように

  • 解決済

    tableview section でエラー

    コードimport UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewD

  • 解決済

    Realmで値の保存を遅らせたい

    現在以下の画面のようにtableviewのセルに3つtextfieldがあります。 そして画面右上のOKが押されるとtextfieldの値がrealmに保存されるよう

  • 解決済

    【swift3】アプリが落ちる【アンラップ】

    乱数を使ったクイズアプリを作っています。 textFieldに0~100までの数字を入力してボタンをタップ。 2回以内にその数字が乱数と一致した場合はUILabelに”正解

同じタグがついた質問を見る

  • Swift

    7435questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4075questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。