55
52

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 5 years have passed since last update.

モーダルウィンドウをStoryboardで設定して、Delegateで値の受け渡しをする

Last updated at Posted at 2015-01-16

iPhone アプリでモーダルウィンドウから更に別なモーダルウィンドウを呼び出して処理をすることがあります。また、モーダルウィンドウのレイアウトは Storyboard で設定しておきたいこともあります。

  1. モーダルウィンドウを表示
  2. モーダルウィンドウを重ねて表示
  3. モーダルウィンドウを閉じる(1枚ずつ、全部)
  4. 表示するモーダルウィンドウを透過(磨りガラス風)
  5. モーダルウィンドウで値の受け渡し(delegate:デリゲート)

画面

完成画面

preview_02.gif

Xcode のStoryboard

スクリーンショット 2015-01-11 12.04.53.png

モーダルウィンドウを表示

presentViewController を利用

Storyboard で設定することもできますが、presentViewController を利用してモーダルウィンドウを作ることができます。
presentViewController で呼び出す UIViewController は、Storyboardでレイアウトすることができます。なので、AutoLayout も利用可能です。

// storyboard で設定したViewを呼び出します
// - idで「second」を指定しています
// - SecondViewController というclassを別で作っています
var secondView:SecondViewController = self.storyboard!.instantiateViewControllerWithIdentifier("second") as SecondViewController

// 透過などが有効になるように設定
secondView.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen

// モーダルウィンドウを呼び出します
self.presentViewController(secondView as UIViewController, animated: true, completion:nil)

モーダルウィンドウを重ねて表示

上記の方法を繰り返すと、表示したモーダルの上に、モーダルウィンドウを表示することができます。例えば下記の様なときに有効です

  1. 入力の選択肢をView表示(1枚目)
  2. 選んだ選択肢での処理を行うViewを表示(2枚目)

表示するモーダルウィンドウを透過

iOS7 からの表現で、下のウィンドウが透けて見えるやつです。重なっていることも利用者に伝えやすいと思います。

  1. 呼び出し側のViewで、呼び出すView(モーダルウィンドウ)の modalPresentationStyle 下記のような設定をします
  2. 呼び出されるView(モーダルウィンドウ)では、UIVisualEffectView を利用します
  3. UIVisualEffectViewはViewの一種なので(であっているかな?)、sendSubviewToBackします
secondView.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
//  SecondView.swift
//  TestAppInputForm02

import UIKit

class SecondViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Dark))
    visualEffectView.frame = self.view.bounds
    self.view.backgroundColor = UIColor.clearColor()
    self.view.addSubview(visualEffectView)
    self.view.sendSubviewToBack(visualEffectView)

    // 以下略
  }

}

モーダルウィンドウを閉じる

閉じ方は2つあります。

1枚閉じる

dismissViewControllerAnimated を使う

import UIKit

class SecondViewController: UIViewController {

  @IBOutlet weak var BackButton: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()
    // 戻る(閉じる)ボタン
    BackButton.addTarget(self, action: "backToMain:", forControlEvents: .TouchUpInside)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  func backToMain(sender: AnyObject?) {
    self.dismissViewControllerAnimated(true, completion: nil);
  }
}

全部閉じる

モーダルウィンドウは数枚重ねることもあります(例:投稿ボタンを押したら、投稿の種類を選ぶボタンがあり、どれかのボタンを押したら投稿用のウィンドウが出てくる)。この時に、2回目のView(例でいうと投稿用のウィンドウ)から一番最初のViewに戻りたい or 保存などの処理をしたい時です

rootViewController を利用して閉じる

class ThirdViewController: UIViewController {
  @IBOutlet weak var AllCloseButton: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()

    // ボタンの設定
    AllCloseButton.addTarget(self, action: "allClose:", forControlEvents: .TouchUpInside)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  func allClose(sender: AnyObject?) {
  UIApplication.sharedApplication().keyWindow.rootViewController?.dismissViewControllerAnimated(true, completion: nil)
  }
}

モーダルウィンドウで値の受け渡し

delegate(デリゲート:委譲)を使います。
値の流れは

  1. モーダルウィンドウ(呼び出されたウィンドウ、View)
  2. モーダルウィンドウを呼び出したView(rootview、実際の処理をする)

となります。

モーダルウィンドウにdelegateを書く

  • protocolを設定
  • delegateのviewを設定
import UIKit

@objc protocol ModalViewDelegate {
  func saveText(textdata:String)
}

class ThirdViewController: UIViewController {

  var delegate:ModalViewDelegate! = nil

  @IBOutlet weak var InputTextThird: UIPlaceHolderTextView!
  @IBOutlet weak var SaveButton: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()

    // ボタンの設定
    SaveButton.addTarget(self, action: "saveSubmit:", forControlEvents: .TouchUpInside)

    // rootViewからdelegate を設定する
    var rootView  = UIApplication.sharedApplication().keyWindow.rootViewController as ViewController
    self.delegate = rootView
  }

  func allClose(sender: AnyObject?) {
    UIApplication.sharedApplication().keyWindow.rootViewController?.dismissViewControllerAnimated(true, completion: nil)
  }

  func saveSubmit(sender: AnyObject?) {

    var inputText:String = InputTextThird.text
    self.delegate.saveText(inputText)

    // 閉じる
    self.allClose(sender)
  }
}

受け取り側に実際の処理を書く

  • delegate を書いておく
  • delegate の処理を書く
import UIKit

class ViewController: UIViewController, ModalViewDelegate{

  override func viewDidLoad() {
    super.viewDidLoad()
  }

  func saveText(textdata:String){
    ImutView.text = textdata
  }
}

ファイル

呼び出し元

ViewController.swift
import UIKit

class ViewController: UIViewController, ModalViewDelegate{

  @IBOutlet weak var TestWebView: UIWebView!
  @IBOutlet weak var ImutView: UIPlaceHolderTextView!
  @IBOutlet weak var SaveButton: UIButton!


  override func viewDidLoad() {
    super.viewDidLoad()

    // TextViewの設定
    ImutView.placeHolder = "本文です。"
    ImutView.placeHolderColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.5)

    // ボタンの設定
    SaveButton.addTarget(self, action: "click:", forControlEvents: .TouchUpInside)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  func click(sender: AnyObject?) {
    var secondView:SecondViewController = self.storyboard!.instantiateViewControllerWithIdentifier("second") as SecondViewController

    secondView.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen

    self.presentViewController(secondView as UIViewController, animated: true, completion:nil)
  }

  func saveText(textdata:String){
    ImutView.text = textdata
  }
}

呼び出されるUIView:1

SecondView.swift
import UIKit

class SecondViewController: UIViewController {

  @IBOutlet weak var BackButton: UIButton!
  @IBOutlet weak var ToThirdViewBbutton: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()

    let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Dark))
    visualEffectView.frame = self.view.bounds
    self.view.backgroundColor = UIColor.clearColor()
    self.view.addSubview(visualEffectView)
    self.view.sendSubviewToBack(visualEffectView)

    BackButton.addTarget(self, action: "backToMain:", forControlEvents: .TouchUpInside)
    ToThirdViewBbutton.addTarget(self, action: "toThird:", forControlEvents: .TouchUpInside)
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  func backToMain(sender: AnyObject?) {
    self.dismissViewControllerAnimated(true, completion: nil);
  }

  func toThird(sender: AnyObject?) {
    var thirdView:AnyObject! = self.storyboard?.instantiateViewControllerWithIdentifier("third")
    self.presentViewController(thirdView as UIViewController, animated: true, completion:nil)
  }
}

呼び出されるUIView:2

ThirdView.swift
import UIKit

@objc protocol ModalViewDelegate {
  func saveText(textdata:String)
}

class ThirdViewController: UIViewController {

  var delegate:ModalViewDelegate! = nil

  @IBOutlet weak var ThisCloseButton: UIButton!
  @IBOutlet weak var AllCloseButton: UIButton!
  @IBOutlet weak var InputTextThird: UIPlaceHolderTextView!
  @IBOutlet weak var SaveButton: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()

    // TextViewの設定
    InputTextThird.placeHolder = "3枚目のViewです。ここに本文を書き、1枚目に送ります"

    // ボタンの設定
    ThisCloseButton.addTarget(self, action: "backToMain:", forControlEvents: .TouchUpInside)
    AllCloseButton.addTarget(self, action: "allClose:", forControlEvents: .TouchUpInside)
    SaveButton.addTarget(self, action: "saveSubmit:", forControlEvents: .TouchUpInside)

    // rootViewからdelegate を設定する
    var rootView  = UIApplication.sharedApplication().keyWindow.rootViewController as ViewController
    self.delegate = rootView
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  func backToMain(sender: AnyObject?) {
    self.dismissViewControllerAnimated(true, completion: nil);
  }

  func allClose(sender: AnyObject?) {
    UIApplication.sharedApplication().keyWindow.rootViewController?.dismissViewControllerAnimated(true, completion: nil)
  }

  func saveSubmit(sender: AnyObject?) {

    var inputText:String = InputTextThird.text
    self.delegate.saveText(inputText)

    // 閉じる
    self.allClose(sender)
  }
}

開発環境

  • Xcode 6.0(6A313)
  • iOS 8
55
52
1

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
55
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?