てくてくテック

気ままに開発のメモを書いていこうと思います。主にSwiftかと。

Viewを出したり消したりしたい

ゲームの設定画面を作りたい

はじめに

こんにちは、takenoteです。 今回もボードゲームのアプリを作成してみながらSwiftの勉強をしていきます。

どこから手をつけていいものかわかりませんが、 とりあえずゲームプレイ前の初期設定画面の作成を試みます。

今回の内容

以下のような画面の作成を目指します。

f:id:takenote-y:20180212165337p:plain
今回のゴール

この画面の実現のために以下の3つの項目を今回の記事でお話しします。

UIのゴール

 ・人数を決めるためのギミックを用意する

 ・名前を入力するためのCustomViewを作成する

 ・人数に応じてCustomVIewを出したり消したりする

またこの画面において期待される機能は以下のようなものです。

動作のゴール

 ・上にあるPickerViewを回すと画面下部のPlayerName入力用のCustomViewが出たり消えたりする

 ・下にあるGameStart!のボタンを押すと"Player人数", "Playerの名前"の情報が次のViewControllerに引き継がれる

今回は画面遷移のところまではいかないため、動作のゴールとしては一つめのみを記載します。 では本題にいきましょう。

人数を決めるためのギミックを用意する

今回はPlayer人数が2~6人だったこともあり、選択するとプルダウンメニューが出て、人数を選ぶUIがよいのかなーとか思ってました。 ちなみに普段はAndroidユーザーです。

人数を選択するためのUIには様々な種類が存在しているかと思います。僕がパッと思いついたのは以下の3つでした。

 1. プルダウン型の選択UI

 2. ラジオボタン

 3. ロールみたいになってるやつ

あれなんですね、、、iOSって標準ライブラリでプルダウン型のUIもラジオボタンも用意されてないんですね。。。 実現することは普通に可能なようで、少し調べて見たら以下のような記事が出てきました。

qiita.com

dev.classmethod.jp

一方でロールみたいにして選択するあれはPickerViewというもので標準的に搭載されているみたいです。

f:id:takenote-y:20180212164822p:plain
X codeの右下にあるViewを選ぶあそこです

使い方は調べてみるとたくさん出てきますね。

qiita.com

という訳で今回は人数選択にこいつを用いることにします。 人数選択のUIにこだわるのは一周回ってきてデザイン面のブラッシュアップをしたくなった時にすることにします。

ちなみにこのPickerView、本来はいくつか列を持って組み合わせで選択ができるようです。 今現在は人数しか入力させていませんが、特殊ルールやモード選択などができるようになれば、その時にはもっと有効に使える日がくるかもしれません。

名前を入力するためのCustomViewを作成する

以下の方法でLabelとTextViewが横に並んだだけのCustomViewを作成しました。

  1. レイアウトを決めたxibファイルを作成する

 2. 対応するswiftファイルを作成する

 3. StoryBoard上に配置する

基本的には"X code CustomView"で調べるとすぐに実現方法がわかるのですが、 一点だけ見落としてしまい、なかなか前に進むことができないことがありました。

Viewを選択した時に出てくるIdentity Inspectorではなく、File's Ownerを選択した時に出てくるIdentity InspectorのところにあるClassに対応するのところにswiftファイルの名前を入力してください。

f:id:takenote-y:20180212171344p:plain
ここ見落としやすいので気をつけてください

やらしいことにViewを選んでも全く同じような画面が表示されてしまうので、できたできた、と思って次に行ってしまうんですよね。

swiftファイルの中身はこんな感じでとてもシンプルです。

import UIKit

class TestCustomView: UIView {

    @IBOutlet weak var leftLabel: UILabel!
    @IBOutlet weak var textView: UITextField!

    //コードから生成したときに通る初期化処理
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.commonInit()
    }
    
    //InterfaceBulderで配置した場合に通る初期化処理
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.commonInit()
    }
    
    fileprivate func commonInit() {
        //MyCustomView.xibファイルからViewを生成する。
        //File's OwnerはMyCustomViewなのでselfとする。
        guard let view = UINib(nibName: "TestCustomView", bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView else {
            return
        }
        view.frame = self.bounds
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        self.addSubview(view)
    }
    
}

人数に応じてCustomVIewを出したり消したりする

「数字を設定するためのPicker」と「出したり消したりするCustomView」の用意が終わりました。 今から用意したCustomViewを出したり消したりします。

customViewの表示を出したり消したりするためには、Viewのもつプロパティであるalphaをいじるようです。 今回はPickerViewの値に応じて数を変更させたかったので、PickerViewのメソッド内に処理を入れています。

class InitialSettingViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource{

    //上のドラムと、その上下に表示する文字Labelです
    @IBOutlet weak var pickerView: UIPickerView!
    @IBOutlet weak var onPickerLabel: UILabel!
    @IBOutlet weak var belowPickerLabel: UILabel!
    @IBOutlet weak var goButton: UIButton!
    
    
    //名前を入力するためのTextViewです。左にあるLabelとセットです。
    @IBOutlet weak var nameInputView0: TestCustomView!
    @IBOutlet weak var nameInputView1: TestCustomView!
    @IBOutlet weak var nameInputView2: TestCustomView!
    @IBOutlet weak var nameInputView3: TestCustomView!
    @IBOutlet weak var nameInputView4: TestCustomView!
    @IBOutlet weak var nameInputView5: TestCustomView!
    
    let numOfPlayer: [[Int]] = [[2,3,4,5,6]] //ドラムに表示する数字です。ドラムは列を増やせるため今後ちょっとしたルールを追加するのにも使えます。
    var inputNameViews: [TestCustomView] = []   //TextViewを一括操作するための配列です
    var defaultNumOfPlayer: Int = 2                            //表示するTextVIewの数の初期値
    
 override func viewDidLoad() {
        super.viewDidLoad()
        goButton.setTitle("Game Start!!", for: .normal)
        onPickerLabel.text = "プレイ人数を選択してください"
        belowPickerLabel.text = "人でプレイ!!"
        inputNameViews = [nameInputView0, nameInputView1, nameInputView2, nameInputView3, nameInputView4, nameInputView5]
        
        var i = 1
        for view in inputNameViews{
            if(i > defaultNumOfPlayer){
                //ドラムで選択された数値以上のTextViewは表示されない。初期設定は2人にしたのでそれ以上のPlayerの入力窓は非表示にした。
                view.alpha = 0
            }
            view.leftLabel.text = "Player" + i.description + ": "
            view.textView.placeholder = "Input your name"
            i += 1
        }
    }

//コンポーネントの個数を返すメソッド
    @IBOutlet weak var numOfPlayersPicker: UIPickerView!
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return numOfPlayer.count
    }

    //コンポーネントに含まれるデータの個数を返すメソッド
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return numOfPlayer[component].count
    }

    //データを返すメソッド
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return numOfPlayer[component][row].description
    }

    //データ選択時の呼び出しメソッド
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        defaultNumOfPlayer= numOfPlayer[component][row]
  //ここで取れた値を元に、CustomViewのalpha値を変更する。
        showOrHideNameInputView(component: component, row: row)
    }
    


 //CustomViewを出したり消したりするmethod
    func showOrHideNameInputView(component: Int, row: Int){
        for i in 0 ..< numOfPlayer[component][row]{
            inputNameViews[i].alpha = 1
        }
        for i in numOfPlayer[component][row] ..< inputNameViews.count{
            inputNameViews[i].alpha = 0
        }
    }
}

これで実装完了です。 ViewControllerを超えた値の持ち越しは次回に回します。

読んでくださってありがとうございました。