リブートキャンプ by Swift 目次

 

 予告通り地図画面起動ボタン付けます。

 

 まずはボタンの画面への貼り付けから。

 この場合、ライブラリからボタンを探さないといけないんだけど、前回のTap Gesture Recognizerを探した要領で、検索ボックスに「but」あたりを入れれば一発で出てきます。

 

 この見つけた項目をCanvasビューにドラッグ&ドロップするのはTap Gesture Recognizerの時と同じ。

 

 

 ちょっと違う点は、ボタンの場合、ドロップした位置にボタンが表示されるってこと。ボタンはTap Gesture Recognizerと違って画面の一部になるんで、ビューコントローラが画面を表示した際に、どう見えるのか確認できるようになってるんですよ。

 

 

 画面に貼り付けたら、あとはボタンのタップに合わせた反応を設定するだけっす。

 で、例のターゲットアクションデザインパターンなわけですよ。

 ボタンもTap Gesture Recognizer同様、他オブジェクトとの連携にこのパターン使ってます。ターゲットアクションデザインパターンがわからん人は「タップしてドン」を読みましょう。

 なので、ボタンの反応もTap Gesture Recognizerと同じで、ターゲットとアクションを設定するってことになる。

 異なる点はTap Gesture Recognizerだと、アクションに対する引き金はタップだけだったんだけど、ボタンにはいろいろな引き金があるってとこ。

 

 

 どの引き金に対して、どうアクションするかはプログラマ次第ってわけで、それぞれにターゲットとアクションを指定できます。

 で、今回なら、Touch Up Inside(タッチした指先がボタン上で放された)時に地図を表示が適切なんで、こいつにターゲットとアクションを指定します。

 前回、Tap Gesture RecognizerでやったみたいにTouch Up InsideからView Controllerに向けて接続線を伸ばせば、ドロップ時に現れるメニューからshowAsViewメソッドをアクションに指定することができます。

 

 

 ちゃんと設定できたら、ボタンのConnectionsインスペクタはこんな感じになる↓

 

 

 これで

 

  画面にボタンを置く

  ボタンがタップされたらshowAsViewメソッドを呼び出す

 

という処理がストーリーボードで記述されたことになるわけっすな。

 前回のサンプル:http://tetera.jp/xcc/book-sample/storyboard-2.zipを元に、上の手順に従ってボタンを加え、Runしちゃってみてください。

 画面タップの他にボタンをタップでも地図画面が出るようになります。

 

 

 てなわけで、ボタン用意できたなら画面全体のタップ反応は不要っすね。ボタン以外の画面タップは反応しなくしちゃいましょう。

 

 今現在は、ViewControllerのshowAsViewメソッドが、ボタンおよびTap Gesture Recognizerの両方のターゲットアクションとして登録されてる状態っす。確認したい人はView Controller選んで、Connectionsインスペクタの画面を見ましょう。   

 Referencing Outlut Collectionsグループで、showAsView項目に2つのオブジェクトが接続されてるのがわかると思う。

 


 なので、このうちのTap Gesture Recognizerとの接続を切ればボタン以外の画面タップは反応しなくなります。

 接続を切るのは、接続項目の横にあるxマークをクリックするだけです。

 

 

 ま、これで全然問題ないんですが、そもそもTap Gesture Recognizer自体が不要なわけですよ。なのでTap Gesture Recognizer自体を削除しましょう。

 これはoutlineビューでTap Gesture Recognizer項目を選んで、deleteキーでOK。

 

 Runするとボタン以外反応しなくなったはず。

 

サンプル:

 http://tetera.jp/xcc/book-sample/storyboard-3.zip

 

 ちなみにサンプルではボタンのタイトルを「Button」から「地図」に変えてるけど、これはcancasビュー上のボタンをダブルクリックすれば変更できます。

 

 ボタンを選んだ状態でAttributesインスペクタで変更でも可。どっちでも好きな方でやってください。

 

 

 ViewController.swiftでソースコードとして書くなら、こんな感じっす。ボタンの矩形の値は適当。

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 150, y: 250, width: 50, height: 44)
        button.addTarget(self, action:#selector(showAsView),
                for: .touchUpInside)
        button.setTitle("地図", for: .normal)
        self.view.addSubview(button)
    }

 

 これがストーリーボード側でInterface Builderを使って記述されたことになるわけですな。

 

 で、いよいよストーリーボードを使うメリットのド本命。Auto Layoutをストーリーボードに記述する方法っす。

ストーリーボードでのAuto Layout記述

 「ダイナミックなレイアウト」で紹介したNSLayoutConstraintの定義をストーリーボードに記述しようって話っす。

 例えば、ボタンを画面の真ん中にしたい時、ソースコードでAuto Layoutを使う場合は、作成したボタン(button)に対して次のような記述が必要になるわけですが…

 こいつをストーリーボードで記述してみます。

                ・・・
        button.setTitle("地図", for: .normal)
        self.view.addSubview(button)
        //  Auto Layout機能追加
        button.translatesAutoresizingMaskIntoConstraints = false
        var constraints = [NSLayoutConstraint]()
        //  横の制約を作成しconstraintsに追加する
        let h_constraint = NSLayoutConstraint(
            item:button, attribute:.centerX,
            relatedBy:.equal,
            toItem:self.view, attribute:.centerX,
            multiplier:1, constant:0)
        constraints.append(h_constraint)
        //  縦の制約を作成しconstraintsに追加する
        let v_constraint = NSLayoutConstraint(
            item:button, attribute:.centerY,
            relatedBy:.equal,
            toItem:self.view, attribute:.centerY,
            multiplier:1, constant:0)
        constraints.append(v_constraint)
        //  制約群を有効にする
        NSLayoutConstraint.activate(constraints)

 

注意)こんな風にダイレクトに記述する方法の他にVisual Format Languageて記述法を使う方法もあります。こっちの方が記述が簡略化できるけど、さらなる文法覚える必要があります。興味がある人はAuto Layout Guideを読んでみましょう。Advanced Auto LayoutのProgrammatically Creating ConstraintsやAppendexで紹介されてます。

 

 てなわけで、さっそく実行。

 まず、canvas画面のボタンが小さすぎて操作しにくい場合は、適度なサイズにcanvasビューをズームしときましょう。

 

 

 でもって、controlキーを押しながらcanvasビュー上のボタンをクリックし、そのままドラッグして線を引っ張り出します。

 

 

 で、この線をドラッグでボタンが置かれてる親ビュー(つまりボタンの枠外)まで伸ばしたところでドロップ。

 これでボタン(ドラッグ元)と親ビュー(ドロップ先)との位置関係制約(NSLayoutConstraint)を作りたいんだってことになり、んじゃ、どういう拘束なんだよとポップアップメニューが出るんでCenter Horizontally in Safe Area項目(親ビュー側の水平線中央とボタンの水平線中央を合わせる)を選びます。

 ちなみにSafe Areaってのは最近導入された領域で、オブジェクトが占める画面領域のうち、ユーザーの操作に支障が出そうにない領域を指します。最近のiOSは画面端からのフリップでいろいろシステム側が動作する(コントロールパネル出したりとか)ので、そういった画面端なんかを含まない領域を指します。

 

 

 とにかくこれで横位置の設定が完了。

 で、これだけだと横位置しか設定されてないから、拘束しきれないよ〜と注意されるので、再びボタン上でcontrolキー+クリックして線引っ張り出して、親ビューの上で放してメニューからCenter Vertically in Safe Area項目を選んでください。

 

 

注意)shiftキー押しながらクリックで、複数の項目の選択を追加したり解除したりできます。この場合、メニューを閉じるときはenterキーを使う。そのまま閉じちゃうとキャンセル扱いになる。
 

 これで中央位置への拘束の設定は完了。

 だけど、元々のボタンの位置が画面中央でなければワーニングマーク(注意だけど致命的じゃない)が出ます。

 

 

 これは「中央位置への拘束が指定されたけど、いまのボタンの位置って中央じゃないっすよ」って注意。この場合、選びうる選択肢としては

 

 1、画面パーツの位置を、指定した制約の位置になるよう修正

 2、制約側のパラメータを、今の画面パーツの位置になるよう修正

 3、制約破棄

 

があります。今回の場合は中央配置させたいので選ぶのは1ですね。

 さっきの注意マークをクリックし、表示された問題点リストの項目横にあるワーニングマークをクリックしましょう。

 修正方法の候補リストが表示されます。

 

 一番上のUpdate framesが「画面パーツの位置を指定した制約の位置になるよう修正」っす。これで注意は消え「地図」ボタンは、どのiPhone、iPadでも画面の中央に配置されるようになる。

 Swiftで記述する場合のめんどくささが嘘のよう。

 しかも、横置きとか縦置きとか、実行するiPhoneやiPadの種類も選べて確認できるようになってもいます。ビバ、ストーリーボード!

 

 

 ちなみに拘束(NSLayoutConstraint)はoutlineビューでは項目、canvasビューでは拘束線として表示されます。Tap Gesture Recognizerの時と同じように選択、deleteキーで削除したりもできる。選択してAttributesインスペクタで拘束パラメータを変更ってなこともできますよ。

 

 

 いろいろ試してみてちょ。

 

サンプル:

 http://tetera.jp/xcc/book-sample/storyboard-4.zip

 

 シミュレータで実行でもよろしあるよ。

AD

リブートキャンプ by Swift 目次

 

 

 

 

 まさかの癌宣告で前回から1か月以上あいちゃったけど、予告通りストーリーボードの話。

 

 

 ちなみに抗がん剤治療の副作用で、冷たいものに触ると指先がビリビリします。なので部屋を暖かくしてからMacBook Proのトラックパッドを触るようにしてる。

 

 

 

 

 

ストーリーボード

 

 

 ストーリーボードってなんだというと、「スクリプトエンジンっぽい」で作った辞書を使った脚本オブジェクトみたいなもんです。

 

 

 あの時は、アプリで表示させるビューやその動作を辞書に脚本として記述して、それを読み出して実行するプログラムを作ったわけですが、ストーリーボードも同じように、画面上にどんなビューを出したり、タップを通知したりということを記述できたりします。

 

 

 で、こいつはSwiftのプログラムコードのように、テキストエディタを使って記述するのではなく、Interface BuilderというXcodeに組み込まれた専用のエディタを使って記述するようになってます。

 

 

 でもって、その記述したものをファイルとして保存して任意のタイミングで読み込んで利用する。

 

 

 

 

 

.storyboardファイル

 

 

 それが.storyboardって拡張子のファイルなんだけど、実はXcodeのiPhoneアプリ用プロジェクトのテンプレートは全て、この.storyboardファイルを利用するようになってます。

 

 

 それがこのMain.storyboardってファイル。これまで作ったプロジェクトにも入ってて、ナビゲーションエリアのMain.storyboardを選ぶと表示されます。

 

 

 

 

 

 

 

 

 

 

サンプル:

 

 

http://tetera.jp/xcc/book-sample/storyboard.zip

 

 

 

 

 

 エディタエリアに表示されてる画面はInterface Builderのもので、左の領域をoutlineビュー、右の領域をcanvasビューと呼びます。

 

 

 outlineでストーリーボードに記述されているオブジェクトの一覧を階層構造で見せ、canvasで、それらのオブジェクトが実際のiPhoneの画面をどう表示するかを見せてるわけですよ。

 

 

 でもって、どっちのビューでもオブジェクト単位で選択ができるようになってて、互いに連動してハイライトされるようになってもいます。

 

 

 

 

 

 

 

 

 

 

 

 

 

 で、そのまた右のユーティリティエリアでは、選択されたオブジェクトの情報が表示されるという具合。

 

 

 

 

 

 

 



 んじゃ、そのMain.storyboard様には何が記述されてるかというと、ViewControllerオブジェクトの作成なんですな。

 そういうわけで、今回のプロジェクトのMain.storyboardを選んだエディタエリアには、ViewControllerオブジェクトと、そいつが持つUIView(self.view)が表示されていることになります。

 

 

 本当にそうなのか疑う人はoutlineでView Controller項目を選んで、ユーティリティエリアでIdentityインスペクタ画面を表示させてみましょう。

 

 

 classのところがViewControllerってなってることが確認できるでしょう。

 

 

 

 

 

 

 

 

 

 

 以前「こんにちは世界」で触れ、これまで説明していなかった

 

 

 

 

 

 このアプリは、起動するとViewControllerオブジェクトが1つ用意されるようになってるんですよ

 

 

 

 

 

 に対して当然湧き上がるであろう疑問、「じゃあ、なんで、アプリは起動するとViewControllerオブジェクトを用意するのか?」の仕組みがこれです。

 

 

 

 

 

 答え:Main.storyboardでViewControllerを作れって指定されてるから。

 

 

 

 

 

 でもって、プロジェクトでアプリ起動時にMain.storyboard読み込んで使えって指定してるから。

 

 

 ちなみに、どこでMain.storyboardが利用されるように指定されてるかというと

 

 

 ここ↓

 

 

 

 

 

 

 

 

 

 

 ここに指定された名前と拡張子.storyboardを組み合わせたファイルが、アプリ起動時に読み込まれて利用されるようになっている。

 

 

 今回ならMain.storyboardファイルがアプリ起動時に読み込まれて利用されるわけですよ。

 

 

 なので、例えば、このMain.storyboardでViewControllerじゃなく地図画面用であるMapViewControllerを作るように記述すれば、アプリ起動時に地図画面を表示するようにだってできます。

 

 

 そこらへんは追い追いやるとして、とりあえずは手馴しとしてViewController.swiftのviewDidLoadメソッドで記述した、タップの見張りと通知なんかをMain.storyboardで記述してみることにしましょう。

 

 

 ↓こいつね。

 

 

 

class ViewController: UIViewController,

    ・・・



    override func viewDidLoad() {

        super.viewDidLoad()

        self.view.addGestureRecognizer(UITapGestureRecognizer(

           target: self, action: #selector(showAsView)))

    }



 

 

 

 UITapGestureRecognizerの作成とself.viewへの登録、そしてtargetとactionの設定をストーリーボードで記述するわけです。

 

 

 

 

 まずはUITapGestureRecognizerの作成とself.viewへの登録から。

 

 

 

 

 どうやるかというと、ユーティリティエリア下にあるライブラリエリアに表示されてるTap Gesture Recognizerという項目を、エディタエリアのcanvasビューのViewにドラッグ&ドロップしてやります。

 

 

 

 

 

 

 

 

 

 1、ライブラリエリアでObjectライブラリを選択してオブジェクト群を表示させる。

 

 

 

 

 2、表示された項目からTap Gesture Recognizer項目を探し、これをcanvasビュー上のViewにドラッグ&ドロップする。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 Viewはoutlineの階層を見ると察しがつくと思うけど、ViewControllerの持ってるUIView、つまりself.viewを意味してます。これで

 

 

 

 

 

 

 

 

 

  self.view.addGestureRecognizer(UITapGestureRecognizer()))

 

 

 

 

 

 

 

 

 

と同じことを記述したことになるんですな。

 

 

 

 

 ちなみに、objectライブラリのTap Gesture Recognizer項をダブルクリックすると、どういうクラスのオブジェクトかわかるようになってます。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 で、これでUITapGestureRecognizer作ってself.viewに登録するまではできたわけですが、これだけだとtarget: self, action: #selector(showAsView)部分が記述できてないわけですよ。

 

 

 

 

 これをどうするか?

 

 

 

 

 ↓これね。

 

 

 

 

 

 

 

 

 

 

        self.view.addGestureRecognizer(UITapGestureRecognizer(

           target: self, action: #selector(showAsView)))

 

 

 

 

 まず必要なのは、ViewController.swiftにテキストエディタを使って記述したshowAsViewメソッドを、ストーリーボードを記述するInterface Builderに認識させること。

 

 

 

 

 

 

 

 

 

@IBAction

 

 

 

 

 そのために一度、ナビゲーションエリアでViewController.swiftを選び、テキストエディタでViewController.swiftのshowAsViewメソッドの前についてる@objc@IBActionに書き換えます。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

class ViewController: UIViewController,

   ・・・

    @objc func showAsView() {

 

 

 

 

 

 ↓
 

class ViewController: UIViewController,

   ・・・

    @IBAction func showAsView() {

 

 

 

 

 

 

 

 

 

 この@IBActionこそが、Interface Builderに対して、このメソッドはターゲットアクションデザインパターンのアクションとして指定可能なメソッドだよって知らせるキーワードなわけですな。ちなみに@IBActionのついたメソッドは@objc指定であることも保証します。

 

 

 

 

 ターゲットアクションデザインパターンや@objcが何かわからん人は「タップしてドン」と前回の「そして委譲へ」を読みましょう。

 

 

 

 

 書き直したら再びナビゲーションエリアのMain.storyboardを選び、outlineビューのView Controller項目を選択し、ユーティリティエリアのConnectionsインスペクタを表示させてみる。

 

 

 

 

 そうすると下の方のRecieved ActionsのグループにshowAsViewの項目が出現するんですな。これがInterface BuilderがshowAsViewメソッドをターゲットアクションデザインパターンのアクションとして指定可能なメソッドとして認識した証拠。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 で、これが出ると、このshowAsViewの項目の右にある◎からドラッグで線を引き出して、outlineビューのTap Gesture Recognizer項目に繋ぐことができるようになります。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 でもって、上の図のようになったところでマウスのボタンを放すと、これでUITapGestureRecognizerオブジェクトのtargetとしてViewControllerが、actionとしてshowAsViewメソッドが設定されることになるわけです。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 つまり、これで

 

 

 

 

 

 

 

 

 

 

        self.view.addGestureRecognizer(UITapGestureRecognizer(

          target: self, action: #selector(showAsView)))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 と同じことが、ストーリーボードに記述できたことになるんですな。

 

 

 

 

 なので、ViewController.swiftのviewDidLoadメソッドで記述したUITapGestureRecognizerオブジェクトの作成とself.viewへの登録は不要になりました。そのままだとストーリーボード、viewDidLoadメソッドの両方でUITapGestureRecognizerオブジェクトを作っちゃってself.viewへ多重登録することになるんで、viewDidLoadメソッド側は消しちゃってください。

 

 

 

 

 ↓こいつね。

 

 

 

 

 

class ViewController: UIViewController,

    ・・・



    override func viewDidLoad() {

        super.viewDidLoad()

        self.view.addGestureRecognizer(UITapGestureRecognizer(

           target: self, action: #selector(showAsView)))

    }



 

 

 

 

サンプル:

 

 

 

 

http://tetera.jp/xcc/book-sample/storyboard-2.zip

 

 

 

 

 

 

 

 

 

 消したらRun!

 

 

 

 

 viewDidLoadメソッドの処理が無いのに、ちゃんと画面タップで地図画面が表示されるはず。

 

 

 

 

 グレート。

 

 

 

 

 

 

 

 

 

 というか、ぶっちゃけ、これくらいならviewDidLoadメソッドにテキストエディタでプログラムコード直接記述する方がよっぽど早いんすけどね。

 

 

 

 

 

 

 

 

 

 違うから!

 

 

 

 

 本来、ストーリーボードを使うメリットは、View上にボタンといったサブビューをAuto Layout使って配置する時に出てくるんだから。

 

 

 

 

 

 

 

 

 

 というわけで、次回は、ストーリーボード上でボタンを配置してタップしたら地図画面が表示されるようにしてみる。

 

 

 

 

 

 

 

AD

パイレーツ・オブ・カリビアン/最後の海賊

 安定のカリビアン品質。オーランド・ブルーム、キーラ・ナイトレイ共にめでたく現場復帰。まあでも今回はハビエル・バルデムですな。ノーカントリーでオカッパの殺し屋役を見て以来のファン。復讐に燃えるスペイン船長やってます。頭の後ろが欠けてて髪が水中のように絶えずゆらゆら動いて不気味。面白かった

 

ガーディアンズ・オブ・ギャラクシー:リミックス

 最強ミックスVol.2だ!カート・ラッセルがお父さんだったとはな。デビッド・ハッセルホフが出ます。キットは出ません。でもってブルーレーの特典映像で踊ってます。ベビー・グルートも可愛い。面白いよ

 

超高速!参勤交代 リターンズ

 行きがあるなら帰りもでしょ。まあ行きだけでもいいかな。

 

ミス・ペレグリンと奇妙なこどもたち

 ティム・バートンにしては大人しめかな。

 

キングコング:髑髏島の巨神

 ウホッ!

 近代兵器対キングコング。というよりスカルクローラ対キングコング。スカルクローラがキモかわいいぞ。スカルクローラのデザイン元ネタはエヴァンゲリオンのサキエルらしい。確かに。あと監督が地獄の黙示録のファンらしくて登場人物にコンラッドとかマーロウとかそれっぽい名前がついてる。

 日本兵グンペイ・イカリの名前はエヴァのシンジ君とゲームクリエイターの横井軍平さんを合わせたらしい。以上WiKiより。面白かった

 

ドクター・ストレンジ

 着実にインフィニティ・ガントレットへ歩みを進めてますな。

 ナルニア国の白い魔女がツルピカ頭でカンバーパッチの師匠として登場します。でもって敵役がマッツ・ミケルセン、人肉は食べません。面白いよ

 

ローグ・ワン/スター・ウォーズ・ストーリー

 安定のスター・ウォーズ・サイドストーリー。デススターはナゼにあんなオオボケの弱点があったかの理由がわかります。まあ後付けですがね。仕込んだのはマッツ・ミケルセン、人肉は食べません。セキュリティドロイドのK-2のデザインが結構好み、こいつあワルだぜ!

 レイア姫がCG合成で出たりもするよ。面白かった

 

X-MEN:アポカリプス

 ファースト・ジェネレーション、フューチャー&パストに続く三部作完結編。

 安定のX-Men品質。

 

ライト/オフ

 ホラー映画っす。ライトを消すと現れる〜。マン・イン・ザ・ミラー(マイコーの歌じゃなく、ジョジョのスタンドの方ね)的な。面白いよ

 

 

AD