11장. 내비게이션 컨트롤러 이용해 화면 전환하기
12장. 테이블 뷰 컨트롤러 이용해 할일 목록 만들기
# 내비게이션 컨트롤러 이용해 화면 전환하기
가. "Editor-Embed in-Navigation Controller"를 선택합니다.
나. library 팔레트에서 "View Controller"를 끌어다가 메인화면 컨트롤러의 오른쪽 빈 공간에 놓습니다.
다. library 팔레트에서 "Bar Button Item"을 찾아 네비게이션 바의 오른쪽에 끌어다 놓습니다. 그리고 Arributes inspector의 system item 에 값을 Edit 등으로 변경합니다.
라. EDIT 버튼을 마우스 오른쪽 버튼으로 클릭한 채 오른쪽의 뷰 컨트롤러에 갖다 놓습니다. 그러면 검은색 창에 Action Segue를 Show로 선택합니다. 그러면 "메인화면"에서 서브화면으로 갔다가 돌아오는 형태를 취하게 됩니다. 그러면 별도의 코딩이 없어도 화면 전환이 가능합니다.
마. 새로운 화면은 뷰 컨트롤러 클래스 파일이 없어, 메뉴에서 File-New-File.. 에서 Cocoa Touch Class를 선택합니다. SubClass는 UIViewController로 하고 클래스명은 ***ViewController로 저장합니다.
바. Main.storyboard 파일에서 새로 추가한 뷰 컨트롤러(화면)을 선택한후, Identity inspector를 클릭한 후, Class에 새로 만든 ***ViewController 를 선택하여 연결시킵니다.
class ViewController: UIViewController {
var images = ["caterpillar.jpg", "child.jpg", "dahlias.jpg", "strawberry.jpg", "woman.jpg"]
@IBOutlet var imgView: UIImageView!
@IBOutlet var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print (images.count)
pageControl.numberOfPages = images.count
pageControl.currentPage = 0
pageControl.pageIndicatorTintColor = UIColor.green
pageControl.currentPageIndicatorTintColor = UIColor.red
imgView.image = UIImage(named: images[0])
}
@IBAction func pageChange(_ sender: UIPageControl) {
print("current page : ")
print (pageControl.currentPage)
imgView.image = UIImage(named: images[pageControl.currentPage])
}
}
사. prepare()함수를 재정의하여 값을 전달하고 전달자가 누구인지는 segue.identifier값을 통해 알 수 있습니다.
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.isOn = isOn
editViewController.textMessage = txMessage.text!
editViewController.delegate = self
}
func didMessageEditDone(_ controller: EditViewController, message: String ) {
txMessage.text = message
}
func didImageOnOffDone(_ controller: EditViewController, isOn: Bool) {
self.isOn = isOn
if isOn {
imgView.image = imgOn
} else {
imgView.image = imgOff
}
}
}
아.데이터를 전달할 경우, delegate역할의 프로토콜을 작성 및 프로토콜내 함수 정의
import UIKit
protocol EditDelegate {
func didMessageEditDone(_ controller : EditViewController, message : String )
func didImageOnOffDone(_ controller : EditViewController, isOn : Bool)
}
class EditViewController: UIViewController {
자. didMessageEditDone함수에서 메시지 전달 : txMessage.text = message
차. EditViewController에서 delegate 변수 생성 : var delegate : EditDelegate?
카. 수정화면의 btnDone()함수 를 통해 메인화면으로 값 전달하는 부분 생성 : delegate?.didMessageEditDone(self, message : txMessage.text!)
타. 메인스토리의 ViewController에서 prepare()문에 한줄 추가 : editViewController.delegate = self
//
// ViewController.swift
// Navigation
//
// Created by abdurl on 2023/09/20.
//
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.isOn = isOn
editViewController.textMessage = txMessage.text!
editViewController.delegate = self
}
func didMessageEditDone(_ controller: EditViewController, message: String ) {
txMessage.text = message
}
func didImageOnOffDone(_ controller: EditViewController, isOn: Bool) {
self.isOn = isOn
if isOn {
imgView.image = imgOn
} else {
imgView.image = imgOff
}
}
}
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 delegate : EditDelegate?
var isOn = true
@IBOutlet var txMessage: UITextField!
@IBOutlet var lblWay: UILabel!
@IBOutlet var swIsOn: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
lblWay.text = textWayValue
txMessage.text = textMessage
swIsOn.isOn = isOn
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
@IBAction func btnDone(_ sender: UIButton) {
if delegate != nil {
delegate?.didMessageEditDone(self, message: txMessage.text!)
delegate?.didImageOnOffDone(self, isOn: isOn)
}
//navigationController?.popViewController(animated: true)
_ = navigationController?.popViewController(animated: true)
}
@IBAction func swImageOnOff(_ sender: UISwitch) {
if sender.isOn {
isOn = true
} else {
isOn = false
}
}
}
# 테이블 뷰 컨트롤러 이용해 할 일 목록 만들기
가. 아이폰 모양의 스토리보드의 상단을 드래그 한 후, "delete" 버튼으로 화면에 내용 삭제 : 빈 화면 만들기
나. 프로젝트 내의 ViewControllers.swift파일 삭제
다. Library 팔레트에서 Table View Controller를 선택해서 스토리보드에 올려 놓습니다.
라. 메뉴에서 Editor-Embed in-Navigation Controller를 선택하여 추가(Attributes inspector에서 "is Initial View Controller" 항목에 체크)
마. Library팔레트에서 View Controller를 2개를 선택해서 화면에 추가(화면 2개 추가)
바. Library팔레트에서 "Bar Button Item(바 버튼 아이템)"을 찾아 테이블 뷰 컨트롤러의 오른쪽 윗부분에 배치합니다. "Attributes Inspector"을 클릭한 후, System Item값을 Add로 수정합니다.
사. 바 버튼 아이템을 마우스 오른쪽 버튼으로 클릭하여 새로 추가한 뷰 컨트롤러(마.에서 추가한 화면)로 드래그 합니다. 그리고 뷰 컨트롤러가 전체적으로 파랗게 되면 마우스 버튼을 놓습니다. 그리고 Action Segue 창에서 Show를 선택합니다.
.. 이후 부분에 대해서는 내용이 많고, 책이 정리가 잘 되어 있기에 실제 책을 보거나 영상 강의를 보는 것을 추천합니다. 저도 이 책은 여기까지 마무리 하고 최근 구매한 인프런의 강좌를 듣고자 합니다.
****** 추가 ********
segue 설정으로 show를 선택한 후, 이전화면으로 돌아갈 경우, show는 기존 화면 위에 올려둔 것이라, 현재 화면을 pop시키면 되기에 아래와 같이 어떤 ViewController를 사용하는지 몰라도 동일하게 작동할 수 있다.
@IBAction func btnDone(_ sender: UIButton) {
_ = navigationController?.popViewController(animated: true)
}
***** 목록 삭제 하기 *****
item을 삭제처리하는 부분을 추가하고, 문구를 변경(delete -> 삭제) 로 변경하면 끝.. 그외는 모든 것은 기본 제공.
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
items.remove(at: (indexPath as NSIndexPath).row)
itemsImageFile.remove(at: (indexPath as NSIndexPath).row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
// 문구를 Delete에서 "삭제" 로 변경하는 방법
override func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
return "삭제"
}
******* 목록 삭제하기2 *******
override func viewDidLoad() {
super.viewDidLoad()
// 아래 코드는 주석처리 되어 있었기에, 주석해제만 하면 됨... 즉 // 만 삭제하면 됨
self.navigationItem.rightBarButtonItem = self.editButtonItem
// 아래와 같이 왼쪽에 Edit 버튼을 배치할 수도 있습니다.
//self.navigationItem.leftBarButtonItem = self.editButtonItem
}
***** 목록 편집하기 (목록 순서바꾸기) *****
아래의 함수는 원래 주석되어 제공되는데, 주석을 풀고 실행을 하면... "Edit" 편집버튼을 누르면, 오른쪽에 3줄짜리 버거 버튼이 항목마다 오른쪽에 생긴다. 그리고 순서를 저장해야 한다면, 아래와 같이 코드를 추가해야 한다.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
let itemToMove = items[ (fromIndexPath as NSIndexPath).row]
let itemImageToMove = itemsImageFile[ (fromIndexPath as NSIndexPath).row]
items.remove(at: (fromIndexPath as NSIndexPath).row)
itemsImageFile.remove(at: (fromIndexPath as NSIndexPath).row)
items.insert(itemToMove, at: (to as NSIndexPath).row)
itemsImageFile.insert(itemImageToMove, at: (to as NSIndexPath).row)
}
**** 목록 갱신(추가 항목이 보이지 않는다면..) *****
뷰가 처음 보일때 호출 되는 함수의 순서는 ViewDidLoad -> ViewWillAppear -> ViewDidAppear 순입니다. 하지만, 뷰가 전환되어 나타날 때는 ViewWillAppear -> ViewDidAppear 만 호출됩니다. ! 이것으로 최초 화면 로딩시에만 호출할 내용은 ViewDidLoad에 넣으면 됩니다.
class TableViewController: UITableViewController {
@IBOutlet var tvListView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem
}
// List를 reload 한다.
override func viewWillAppear(_ animated: Bool) {
tvListView.reloadData()
}
........
}
class AddViewController: UIViewController {
@IBOutlet weak var tfAddItem: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func btnAddItem(_ sender: UIButton) {
items.append(tfAddItem.text!)
itemsImageFile.append("pencil.jpeg")
//tfAddItem.text = ""
_ = navigationController?.popViewController(animated: true)
}
}
****** detail View 만들기(상세 페이지 만들기) *****
DetailView 클래스에는 전달값을 받아 처리하는 부분을 정의(단순 문자열을 받거나, 문자열을 키로 해서 파일이나 DB를 읽어 Set)하는 것과 TableListView에서 값을 전달하는 함수를 정의하면 된다.
class TableViewController: UITableViewController {
.......
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if segue.identifier == "sgDetail" {
let cell = sender as! UITableViewCell
let IndexPath = self.tvListView.indexPath(for: cell)
let detailView = segue.destination as! DetailViewController
detailView.receiveItem(items[(IndexPath! as NSIndexPath).row])
}
}
}
class DetailViewController: UIViewController {
......
func receiveItem (_ item : String) {
receiveItem = item
}
}
'개발자 넋두리 > 아이폰개발(Swift)' 카테고리의 다른 글
(문제해결) swift Main.storyboard 파일명 변경시 (1) | 2023.12.22 |
---|---|
[문제해결] Codale 타입에서 does not conform to protocol 'Decodable' (0) | 2023.12.20 |
Do it! 스위프트로 아이폰 앱만들기(9~10장 페이지/탭바 컨트롤) (1) | 2023.10.11 |
Do it! 스위프트로 아이폰 앱만들기(7~8장 웹뷰, 맵뷰 ) (0) | 2023.10.09 |
Do it! 스위프트로 아이폰 앱만들기(5~6장) (1) | 2023.10.06 |