티스토리 뷰

Mobile/ios

[ios] ios 10: Navigation Controller

춘햄 2022. 12. 19. 19:28

직전 포스팅에서 다뤘던 탭 바의 경우, 보통 각 화면이 서로 연관성이 없는 경우가 많다. 

 

그렇지만 앱 생태계에서 대부분의 화면 전환은 해당 뷰가 가지고 있던 데이터 또한 함께 넘겨야 한다. 

 

이를 위해 iOS는 Navigation Controller를 사용하는데, 바로 한번 알아보도록 하자.


우선, 프로젝트를 새로 하나 생성한 뒤에 스토리보드에서 기존 뷰를 드래그하여 선택한 다음에 Editor > embed in > Navigation Controller 를 추가하면 아래와 같이 뷰가 하나 추가되며 연결된 상태가 된다.

 

이제 새로 추가된 뷰의 상단을 클릭하면 해당 Navigation View의 Title을 변경할 수 있다.

 

실습에서 하나의 뷰를 더 사용하여 화면 전환과 데이터 이동을 확인해보려고 하니 아래와 같이 View Controller를 하나 추가한다.

 

첫번째 View에 아래와 같이 Edit 라고 적은 Bar Button Item과 수정이라고 적은 일반 Button 그리고 Text Field와 전구 사진을 넣을 Image View를 추가한다.

 

이후에 edit 버튼과 수정 버튼은 옆 View로 드래그하여 Segue way를 연결해준다.

 

Segue Way 지정 방법

 

세그웨이는 다음의 다섯가지 방법으로 지정할 수 있다.

 

 1) Show: 새로운 뷰 컨트롤러가 스택에 푸시하면서 활성화된다.

 2) Show Detail: [Show]와 매우 비슷하지만, 푸시하는 것이 아닌 replace된다.

 3) Present Modally: 새로운 뷰 컨트롤러를 보여 주는 스타일과 화면 전환 스타일을 결정하여 뷰를 모달 형태로 보여준다.

 4) Present As Popover: 현재 보이는 뷰 컨트롤러 위에 앵커를 가진 팝업 형태로 뷰를 표시한다.

 5) Custom: 개발자가 임의로 지정한 동작을 수행한다.

 

 

이 때, 생성된 Segue way를 선택하여 아래와 같이 Identifier를 명시해주면 한 View가 여러 개의 Segue를 가지고 있을 때 구분하여 동작을 구분해줄 수 있다.

 

이제 새로 생성된 View Controller의 소스 코드를 입력할 파일을 추가하고 해당 View Controller에 연결해주자.

new - file - Cocoa Touch Class

 

이제 마지막으로 아래와 같이 각 View Controller 를 구성해주면, 스토리보드 셋팅은 끝이 난다.


예제는 

 

 1. 메인 화면에서 수정 혹은 edit 버튼을 클릭하여 수정 화면으로 이동하며, 이동 시 클릭한 버튼에 따라 수정화면의 Label Text가 변경된다.

 2. 수정 화면의 버튼을 이용하여 메인 화면의 전구 이미지를 제어하고, 메인 화면에 입력한 텍스트를 그대로 수정화면이 가져온다.

 

의 내용으로 구현한다.


먼저, 수정 화면에서 메인화면으로 이동할 때 수정 화면에서 변경한 데이터(전구 온/오프, 텍스트)가 그대로 메인화면으로 전달될 수 있도록 EditDelegate라는 프로토콜을 하나 작성해준다.

 

◎EditViewController

import UIKit

protocol EditDelegate {
    func didMessageEditDone(_ controller: EditViewController, message: String)
    func didImageOnOffDone(_ controller: EditViewController, isOn: Bool)
}

class EditViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

EditDelegate프로토콜은 메인 ViewController가 위임받아 함수를 재정의하고, 재정의된 함수는 수정화면 > 메인화면으로 넘어갈 때 호출되도록 코드를 작성할 예정이다.


이제 각 Controller에 객체들을 outlet 변수에 연결하고, 이미지 파일과 전구 on/off boolean값을 셋팅해주자.

 

◎ViewController

import UIKit

class ViewController: UIViewController, EditDelegate {
    
    let imgOn = UIImage(named: "lamp_on.png")
    let imgOff = UIImage(named: "lamp_off.png")
    
    var isOn = true
    
    @IBOutlet var txMessage: UITextField!
    @IBOutlet var imgView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        imgView.image = imgOn
    }

}

 

 

◎EditViewController

import UIKit

protocol EditDelegate {
    func didMessageEditDone(_ controller: EditViewController, message: String)
    func didImageOnOffDone(_ controller: EditViewController, isOn: Bool)
}

class EditViewController: UIViewController {
    
    var textWayValue: String = ""
    var textMessage: String = ""
    var isOn = false
    
    var delegate: EditDelegate?
    
    @IBOutlet var swIsOn: UISwitch!
    @IBOutlet var txMessage: UITextField!
    @IBOutlet var lblWay: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        lblWay.text = textWayValue
        txMessage.text = textMessage
        swIsOn.isOn = isOn
        // Do any additional setup after loading the view.
    }

}

다음으로 SegueWay가 화면을 전환할 때, 해당 버튼의 Identifier에 따라 수정 화면의 텍스트 레이블 동적으로 변경해주기 위한 코드와 EditDelegate가 가지고 있는 메서드를 재정의 해준다.

 

◎ViewController

import UIKit

class ViewController: UIViewController, EditDelegate {
    
    let imgOn = UIImage(named: "lamp_on.png")
    let imgOff = UIImage(named: "lamp_off.png")
    
    var isOn = true
    
    @IBOutlet var txMessage: UITextField!
    @IBOutlet var imgView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        imgView.image = imgOn
    }
    
    // 세그웨이를 이용하여 화면 전환
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let editViewController = segue.destination as! EditViewController

        if segue.identifier == "editButton" { // 버튼을 클릭한 경우
            editViewController.textWayValue = "segue: use button"
        } else if segue.identifier == "editBarButton" {
            editViewController.textWayValue = "segue: use bar button"
        }

        editViewController.textMessage = txMessage.text ?? ""
        editViewController.isOn = isOn
        editViewController.delegate = self
    }

    func didMessageEditDone(_ controller: EditViewController, message: String) {
        txMessage.text = message
    }
    
    func didImageOnOffDone(_ controller: EditViewController, isOn: Bool) {
        if isOn {
            imgView.image = imgOn
            self.isOn = true
        } else {
            imgView.image = imgOff
            self.isOn = false
        }
    }

}

이 때, EditViewController에서 선언한 delegate 변수에 해당 ViewController 객체를 반드시 할당해줘야 한다.


마지막으로 수정 화면에서 전구의 On/Off Action 함수와 완료 버튼을 눌렀을 때, EditDelegate 프로토콜의 함수를 호출하게끔 하면 완성이다.

 

◎EditViewController

import UIKit

protocol EditDelegate {
    func didMessageEditDone(_ controller: EditViewController, message: String)
    func didImageOnOffDone(_ controller: EditViewController, isOn: Bool)
}

class EditViewController: UIViewController {
    
    var textWayValue: String = ""
    var textMessage: String = ""
    var isOn = false
    
    var delegate: EditDelegate?
    
    @IBOutlet var swIsOn: UISwitch!
    @IBOutlet var txMessage: UITextField!
    @IBOutlet var lblWay: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        lblWay.text = textWayValue
        txMessage.text = textMessage
        swIsOn.isOn = isOn
        // Do any additional setup after loading the view.
    }
    
    
    @IBAction func swImageOnOff(_ sender: UISwitch) {
        if sender.isOn {
            isOn = true
        } else {
            isOn = false
        }
    }
    
    
    @IBAction func btnDone(_ sender: UIButton) {
        if delegate != nil {
            delegate?.didMessageEditDone(self, message: txMessage.text!)
            delegate?.didImageOnOffDone(self, isOn: isOn)
        }
        
        _ = navigationController?.popViewController(animated: true)
    }
   
}

 

 

 

끝!! 

 

조금은 복잡해 보이지만, 까고 보면 인터페이스를 활용한 데이터의 전달이다. 

 

안드로이드 보다는... 훨 간단하게 구현할 수 있는 거 같다.

'Mobile > ios' 카테고리의 다른 글

[ios] ios 12: 음악 재생 & 녹음  (0) 2022.12.21
[ios] ios 11: Table View Controller  (0) 2022.12.20
[ios] ios 9: Tab Bar  (0) 2022.12.17
[ios] ios 8: Page Control  (0) 2022.12.17
[ios] ios 7: MapView  (0) 2022.12.15
Comments