Swiftで遊ぼう! - 297 - Split View Controller
Swiftで遊ぼう!の古い記事-> Life-LOG OtherSide
質問 : Swiftで遊ぼう! - 252 - Happiness - カスタムViewチュートリアル - Swiftで遊ぼう! on Hatena
これでアプリを立ち上げるとスタンフォード大学の風景が表示されるようになりました。
これではつまらないですよね。プロジェクトのタイトルは「Cassini」です。土星探査衛星から名前をとっているので、イメージ画面の切りかえをしてCassiniが表示されるようにします。
Multiple MVCsの講義で使ったSplit View Controllerを使います。
オブジェクト・ライブラリから「Split View Controller」をドラッグしてMain.storyboardに引っ張ってくると、色々なテンプレートViewがくっついてきます。前の講義では、Split View Controller以外のViewを選択して消去、自分で作ったカスタムViewControllerを繋ぎました。メニューから「Editor -> Embed in -> Navigation Controller」を選んだのを覚えていますか? この作業を省くために、テンプレートViewのNavigation Controllerだけ残します。
SplitViewControllerから「Ctrl + ドラッグ」してImageViewControllerに繋いで「detail view controller」を選びます。
次にNavigation Controllerから「Ctrl + ドラッグ」してメインのViewControllerに繋いで「root view controller」を選びます。
次にMain.storyboardにボタンを配置します。
これも慣れたものです。オブジェクト・ライブラリからボタンをドラッグして3つ並べます。
ボタンをそれぞれ「Earth」「Cassini」「Saturn」と変更してフォントのサイズを適当に大きくsasコンストレイントの設定をします。
それぞれのボタンからSegue(セグエ)を設定するために「Ctrl + ドラッグ」してImageViewControllerに繋ぎます。
ポップアップメニューから「show detail」を選びます。Segueの設定でポイントはアトリビュート・インスペクタにあるIdentifierの設定です。
ボタンの名前に合わせてIdentifierを「Earth」「Cassini」「Saturn」にします。
これで下準備ができました。
次はコーディングですがまた明日。
Swiftで遊ぼう!の古い記事-> Life-LOG OtherSide
質問 : Swiftで遊ぼう! - 252 - Happiness - カスタムViewチュートリアル - Swiftで遊ぼう! on Hatena
今日はSegueのコーディングをします。
Segueのコーディングもある意味、定型化されていて覚えておくべきでしょう。ボタンを配置したメインのViewControllerにコーディングをしていきます。
class ViewController: UIViewController { }
このクラスの中にprepareForSegueとタイプしていくとコーディングのための補完機能が働きます。
これを選べば自動的にoverrideのキーワードが付いてコードを入力する準備状態になります。
そして「定型文」を入力します。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if let ivc = segue.destinationViewController as? ImageViewController { if let identifier = segue.identifier { switch identifier { case "Earth": ivc.imageURL = DemoURL.NASA.Earth ivc.title = "Earth" case "Cassini": ivc.imageURL = DemoURL.NASA.Cassini ivc.title = "Cassini" case "Saturn": ivc.imageURL = DemoURL.NASA.Saturn ivc.title = "Satrun" default: break } } } }
これで準備はできたのですが、このままラン(Cmd + R)してもスタンフォード大学の風景が出たままになっています。
というのも作成されるImageViewControllerのviewDidLoad()内にある次のコードを消す必要があります。
if image == nil { imageURL = DemoURL.Stanford }
これでSegueが動きます。
Earthボタンを押すと
バックしてCassiniボタンを押すと
巨大な画像の一部しか表示されていないのです。
ここでスクロールビューが必要になるということです。
今日はここまで。
Swiftで遊ぼう!の古い記事-> Life-LOG OtherSide
質問 : Swiftで遊ぼう! - 252 - Happiness - カスタムViewチュートリアル - Swiftで遊ぼう! on Hatena
ScrollViewを組み込む最も簡単な方法は当然Xcodeのオブジェクト・ライブラリからUIScrollViewをドラッグするやり方です。これでrootビューの上にジェネリックなスクロールビューが設置されたので、「Ctrl + ドラッグ」してImageViewControllerに引っぱって名前を「scrollView」にしてoutletを作ります。
@IBOutlet weak var scrollView: UIScrollView! { didSet { scrollView.contentSize = imageView.frame.size } }
こういう場合のプロパティ・オブザーバーは常套手段のようです。scrollViewが呼ばれる毎にコンテンツサイズを変化させるようにします。
このoutlet作成で、自動的にrootビュー上にscrollViewがインスタンス化されました。
次はViewControllerが呼ばれた時、viewDidLoad()内でイメージをscrollViewに加える必要があります。
override func viewDidLoad() { super.viewDidLoad() scrollView.addSubview(imageView) }
もう一つ重要なステップがあります。imageViewのサイズでscrollView.contentSizeは変化しますが、imageViewはimageのサイズで変化します。
private var image: UIImage? { get { return imageView.image } set { imageView.image = newValue imageView.sizeToFit() scrollView?.contentSize = imageView.frame.size } }
imageに新しい画像が書き換えられた時にcontentSizeが変化するようにします。この時のポイントは、imageの書き換えは画面の描画と関係なく内部的に発生するかもしれません。そういう場合はscrollViewが存在しないかもしれないので、オプショナル(?)で回避すると言うことです。
たったこれだけ変更を加えただけで、ラン(Cmd + R)してCassiniボタンを押してしばらく待つと(次のマルチスレッドで対処します)、大きな画像をスクロールできるようになりました。
感動です。次はズーミングですね。
- Swiftで遊ぼう!の前書き-> Life-LOG OtherSide
- Swift2.1 & Xcode7.1対応の日本語版アップルチュートリアル!
- Table View実装チュートリアルをXcode7.3で解説
- Core Data シンプルチュートリアル
- 私の本業、オフィシャルなブログ-> Life-LOG
2016年6月6日:加筆していません。2年後のiOS9バージョンの講義と全く同じでした(^_^;)
実はScroll Viewの学習で最も重要なトピックは、iOS API利用におけるデリゲート・メソッドの取り扱いです。
基本的なデリゲーションの説明は上記でしていますが、iOS API利用にこの考え方は欠かせません。ここで6つのステップを説明していますが、API利用のデリゲートはステップ4、5そして6を実装するだけです。
プロトコール利用の場合、必ずデリゲートされているメソッドを全て実装しないとランタイムエラーに陥りますが、API利用の場合、すべてオプショナル扱いになるので使いたいメソッドだけ実装したらいいようです。
Scroll Viewには全部で12個のデリゲーションメソッドがありますが、ZoomingのメソッドのviewForZoomingInScrollView()を実装してみます*1。
先ず、Scrol Viewでデリゲートさせたいメソッドを含んだプロトコールをImageViewController宣言をさせます。これはステップ4になります。
class ImageViewController: UIViewController, UIScrollViewDelegate { ...
次はステップ5で、scrollViewのdelegateプロパティにImageViewController自身を持たせます。ImageViewController上のscrollView宣言部分でdelegate先を指定します。たぶん初心者には分かりにくい説明だと思いますが、これは慣れるしかないでしょう。
@IBOutlet weak var scrollView: UIScrollView! { didSet { scrollView.contentSize = imageView.frame.size scrollView.delegate = self scrollView.minimumZoomScale = 0.03 scrollView.maximumZoomScale = 1.0 } }
そして最後のステップ6はメソッドの実装です。
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? { return imageView }
たったこれだけで画像のズーミングができるようになりました。
今日はデリゲーションの復習でした。
*1:このメソッドは、minimumZoomScaleとmaximumZoomScaleを設定しないと動かないので同時に設定します。