8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UIButtonからUIPickerViewを表示させる方法

Last updated at Posted at 2022-12-21

はじめに

  • 個人で家計簿アプリを作っています!その際、ButtonからPickerを表示、選択から保存までで躓いた部分が多く、記事をあまり見かけなかったので投稿させていただきます
  • 変更した方が良い部分や、もっとうまい書き方等ありましたら、ご指摘いただけると幸いです

全体像

  • 左画面の右下にある丸ボタンで右の画面に遷移
  • 右画面の赤い四角で囲っているトレーボタンを押下するとPickerを表示、選択によって値を画像を変更する
  • 右画面はTableViewを使用、xibでカスタムセルを用意
Screen Shot 2022-12-21 at 22.13.30.png Screen Shot 2022-12-21 at 22.42.52のコピー.png

躓いた点

  • カスタムセルがUIViewを継承していないため、検索でよく出てくる基本的な方法で実装できなかったこと
  • 選択されたpickerの項目を画像に変換し、表示させること

実現できたこと

  • tableviewのカスタムセル内にあるUIButtonをタップした際に、textfield風のPickerViewを表示させること
  • PickerViewで選択した項目によって、ボタンの画像を切り替えること

コード

  • UIButtonを継承したクラスを用意し、PickerViewKeyboardDelegateとUIPickerViewを持たせる
  • 実際にボタンがタップされたときに呼ばれる処理を記載

PickerViewKeyboardクラス

class PickerViewKeyboard: UIButton {
    var delegate: PickerViewKeyboardDelegate!
    var pickerView: UIPickerView!
    
    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    // ピッカーに表示させるデータ
    var data: Array<String> {
        return delegate.titlesOfPickerViewKeyboard(sender: self)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.addTarget(self, action: #selector(didTouchUpInside(_:)), for: .touchUpInside)
    }
    
    @objc func didTouchUpInside(_ sender: UIButton) {
        becomeFirstResponder()
    }
    
    override var inputView: UIView? {
        pickerView = UIPickerView()
        pickerView.delegate = self
        pickerView.dataSource = self
        let row = delegate.initSelectedRow(sender: self)
        pickerView.selectRow(row, inComponent: 0, animated: true)
        
        return pickerView
    }
  • Picker実装の際の必須のコード
extension PickerViewKeyboard: UIPickerViewDelegate, UIPickerViewDataSource {

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return data.count
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return data[row]
    }
}

  • PickerViewKeyboard の delegateのプロトコル
  • pickerが出た時の完了ボタンや、キャンセルボタンの処理など
protocol PickerViewKeyboardDelegate {
    func titlesOfPickerViewKeyboard(sender: PickerViewKeyboard) -> Array<String>
    func initSelectedRow(sender: PickerViewKeyboard) -> Int
    func didCancel(sender: PickerViewKeyboard)
    func didDone(sender: PickerViewKeyboard, selectedData: String)
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) -> String
}

NewCreateLogTableViewCell(カスタムセルのクラス)

class NewCreateLogTableViewCell: UITableViewCell {
// 省略
    // Imageとなってますが、buttonです
    @IBOutlet weak var categoryImage: PickerViewKeyboard!
    
    let dataSource: [String] = ["生活費","経費","娯楽費"]

    override func awakeFromNib() {
        categoryImage.delegate = self
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
// 省略
}

extension NewCreateLogTableViewCell: PickerViewKeyboardDelegate {

    func titlesOfPickerViewKeyboard(sender: PickerViewKeyboard) -> Array<String> {
        return dataSource
    }
    
    func initSelectedRow(sender: PickerViewKeyboard) -> Int {
        return dataSource.count
    }

// pickerが選択された時、画像を切り替える
// 画像名はenumで定義
 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) -> String {
        if dataSource[row] == "生活費" {
                    self.categoryImage.setImage(UIImage(systemName: Category.livingCost.rawValue), for: UIControl.State())
                } else if dataSource[row] == "経費" {
                    self.categoryImage.setImage(UIImage(systemName: Category.expenses.rawValue), for: UIControl.State())
                } else {
                    self.categoryImage.setImage(UIImage(systemName: Category.waste.rawValue), for: UIControl.State())
                }
        return dataSource[row]

    func didDone(sender: PickerViewKeyboard, selectedData: String) {
        //pickerを閉じる処理
        self.endEditing(true)
        print("didDone")
        }
    
    
    func didCancel(sender: PickerViewKeyboard) {
        //pickerを閉じる処理
        self.endEditing(true)
        print("canceled")
    }
}

完成動画

picker完成.gif

終わりに

  • delegateの使い方など、初歩的な部分も含めて学習することができとても良い経験になった
  • まだまだ改善できる部分は数多くあると思うので、改善してより良く記述できるようになりたい
  • 早くアプリを完成まで持っていきたい

参考文献

最後に

弊社では、経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談しましょう!

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?