Ruby Motionチュートリアルやってみた(4)


Ruby Motionチュートリアルをやってます。前回の記事はこちら

Ruby Motionチュートリアルはこちら。

▼開発環境
Ruby 2.5.3
Xcode 10.1
Ruby Motion 5.16

今回は、コンテナについてのお話だそうです。

アプリって基本的に一番したのところにメニューバーがありますよね。iOSではこれをUITabBarControllerと呼ばれるそうです。ちなみに、上部のメニューバーはUINavigationControllerだそうです。

Railsでいったら、部分テンプレートとかlayoutesとかそんな感じのイメージかな?

では、ナビゲーショーションの作成に取り掛かりましょう。

仕様は「Accounts -> An Account -> Inbox -> Message」となることです。

UINavigationControllerは自動的に戻るボタンを処理してくれるらしいので、基本的にはコントローラーをプッシュ/ポップするだけになります。

では、実際にUINavigationControllerを使ってコードを記述していきましょう。AppDelegateでrootViewControllerの設定を変更します。

 ...
 controller = TapController.alloc.initWithNibName(nil, bundle: nil)
 @window.rootViewController = UINavigationController.alloc.initWithRootViewController(controller)
 ...

initWithRootViewController は指定されたコントローラを受け取り、そのコントローラで処理を開始します。

次に、なんか知らんけどサイトにタイトルを追記するらしい。TapControllerを以下のように変更する。

...
 self.view.addSubview @label
 self.title = "Tap"
...

ここで一旦、実行結果を確認しましょう!

画面上部にナビゲーションバーとタイトルが表示されましたね。背景がグレーでわかりづらいけど。この表示は全てのアプリに共通してるんじゃないかな?

見た目的にも重要だけど、ナビゲーションバーをクリックすると別ページに飛ぶようにリンクをつけてみましょう!でなれば、ナビゲートしてないしね!

じゃ、TapControllerにボタンを追加していきましょう。

def viewDidLoad
  ...
  self.title = "Tap"

  right_button = UIBarButtonItem.alloc.initWithTitle("プッシュだよ", style: UIBarButtonItemStyleBordered, target:self, action:'push')
  self.navigationItem.rightBarButtonItem = right_button
end

さてさて、UIBarButtonItemは何をしているかというと、ボタンを作るためのインスタンスを生成しています。

ところで、targetとactionは何をしてるのか。。。

はい、読んでもよくわかりませんでした。。。
要するに、targetとactionでどこにリンクするかを指定してるってことかな?んで、そのやり方が直接確認じゃなくてメソッドを指定していると。。。
念の為、引用しときます。(わかったら誰か教えてください)

target と action の役割は何でしょう?えぇと、これは Ruby の世界へオリジナルの Objective-C SDK が漏れ出てきたものです(´д`) ごく最近まで、Objecive-C で無名関数をコールバックとして渡すことができませんでした。その代替手段として、オブジェクトとオブジェクトから呼び出すメソッドの名前を API に渡しています。私たちはこの処理を Ruby でブロックと lambda で行いますが、悲しいことに古い iOS の API は古くささを示してます。
~中略~
それはさておき、target は action のメソッドを呼び出してもらいたいオブジェクトを指定します。より良いアイディアを得るために TapController へ push メソッドを実装してみましょう!
...
 def push
   new_controller = TapController.alloc.initWithNibName(nil, bundle: nil)
   self.navigationController.pushViewController(new_controller, animated: true)
 end
...
どうでしょう?ユーザがバーのボタンをタップしたときに、target で指定したオブジェクト(このケースでは私たちのコントローラ) の push が呼ばれます。
navigationItem に付け加えると、利用可能な場合には UIViewController は navigationController というプロパティも持っています。ナビゲーションコントローラでは、pushViewController を呼び出すと渡されたコントローラをスタック上にプッシュします。デフォルトでは、ナビゲーションコントローラは戻るボタンも表示します。この戻るボタンは現在のコントローラをポップする処理を行います(通常は、ナビゲーションコントローラ上で popViewControllerAnimated: を私たちが呼び出します)。ちゃんとわかりましたか?

次は、「navigationItem」が出てきましたね。なんでも全てのUIViewControllerには、このnavigationItemがあって、画面上部に表示されている情報にアクセスするための手段になるんだって!

rightBarButtonItemはnavigationItemの中でも右側のボタンを意味してるんだろうね。

んで、そのボタンの内容をさっき指定したrigtht_buttonをいれてる。

もうちょっとコードを記述していきましょう。まだページの中身を作っていないので、移動しても変化がわからないですよね。なので、ページが変わるとタイトルも変わるように変更します。

 def viewDidLoad
   ...
   self.title = "Tap (#{self.navigationController.viewControllers.count})"
   ...
 end

viewControllersが出てきているけど、多分コントローラーを全て取得して配列で返すメソッドじゃないかな?

さぁ、いよいよ実行してみましょう!

うまく動いてます^^パチパチパチ〜♪

さてさて、お次は、「UITabController」に取り掛かりましょう!!

ところで注意が必要なのが「UINavigationController」と「UITabBarController」の大きな違いとして「UITabBarController 」は window の rootViewController として動作することのみをサポートしているという点です。要するに、ナビゲーションコントローラーでタブバーコントローラーをプッシュしてはいけないということです。

では、実際のタブバーコントローラーの記述をしていきましょう。AppDalegateを編集してください。

...
 controller = TapController.alloc.initWithNibName(nil, bundle: nil)
 nav_controller = UINavigationController.alloc.initWithRootViewController(controller)
 tab_controller = UITabBarController.alloc.initWithNibName(nil, bundle: nil)
 tab_controller.viewControllers = [nav_controller]
 @window.rootViewController = tab_controller
...

今回のコードは、特に説明なくて大丈夫ですよね?

じゃ、実行してみましょう。

どこが変わったって??よく見てください!!!ちゃんと下にばーが表示されてるでしょうが!!まぁ、期待はずれかもしれませんね。んじゃ、ちょっとこれを装飾していきましょう!

なんか、navigationItemと同じくUIViewControllerにはtabBarItemってのがあるらしくて、UITabBarItemのインスタンスを受けるらしいよ〜。

UIViewControllerって何でもあるな〜。tabBarItemは、「アイコン」「タイトル」など見た目に関するオプションを指定する時に使います。

TapControllerでinitWithNibName:bundle:をオーバーライドして、次のように編集します。

...
 def initWithNibName(name, bundle: bundle)
   super
   self.tabBarItem = UITabBarItem.alloc.initWithTabBarSystemItem(UITabBarSystemItemFavorites, tag: 1)
   self
 end
 ...

これはUITabBarItemの初期化メソッドらしいです。独自の画像やタイトルを使う場合は、「initWithTitle:image:tag:」を使うらしいです。※画像は、30x30 の黒い透過なアイコンにする必要があるそうです。

initWithTabBarSystemItemはシステムに用意されてるやつを使うやつらしいです。

んで、何でinitWithNibName:bundle:のなかで記述してるのか、チュートリアルに説明がありました。そっか〜って思ったので引用します。

なぜ initWithNibName:bundle: のなかで記述しているのでしょう?コントローラのビューが用意されたかどうかにかかわらず、コントローラが用意されたらできるだけ早く tabBarItem を作成したいからです。もし viewDidLoad に記述した場合、アプリが起動したときにすぐに作成できないかもしれません(ユーザによってコントローラに初めてアクセスがあったときに、タブバーコントローラは子のコントローラをロードします)。

ちなみに、せっかく作ったタブですが、リンク先がないですよね。なので、とりあえずコントローラーだけ作っておきましょう。作る場所は、AppDelegateでしたよね。

...
 other_controller = UIViewController.alloc.initWithNibName(nil, bundle: nil)
 other_controller.title = "Other"
 other_controller.view.backgroundColor = UIColor.purpleColor
 tab_controller = UITabBarController.alloc.initWithNibName(nil, bundle: nil)
 tab_controller.viewControllers = [nav_controller, other_controller]
 @window.rootViewController = tab_controller
 ...

では、最後に実行して、結果を表示してみましょう!

最後にまとめです。

Subway Up
私たちがカバーした範囲は、次のことまで広がりました。
・iOS SDK は子のビューとなるコントローラを含むために UINavigationController と UITabBarController を使用します。
・UINavigationController はスタックをコントロールするために 'pushViewController:animated:' と 'popViewControllerAnimated:' を使います。
・画面上部の青いバーのボタンやそのほかのオプションを変更するのには controller.navigationItem を使用します。
・UITabBarController は子のコントローラをコントロールするために viewControllers= を使用します。注意として、UITabBarController は window の rootViewController としてしか使えません。
・タブのアイコンやタイトルを変更するのには controller.tabBarItem を使用します。


ちなみに、最初からここまでにかかった時間は約6時間です。まとめながらじゃなかったら、もっと早くいけると思います。

サポートしていただけると、泣いて喜びます! 嬉しくて仕事をめちゃめちゃ頑張れます。