꾸준히 안타치기
메모장 만들기(스토리보드) +배경이미지 + 얼럿창이미지추가 본문
스토리보드 화면구성
메모 목록화면 구성
프로젝트를 생성하고, 메인스토리보드를 연다.
기본적으로 생성되어있는 viewController.swift와 메인스토리보드의 뷰컨트롤러를 삭제한다. ->Move to Trash
빈스토리 보드에 네비게이션 컨트롤러를 추가한다.(테이블 뷰 컨트롤러가 자동으로 추가됨)
프로토타입 셀이 선택된 상태에서 인스펙터 탭 -> 높이값 설정 | 테이블뷰전체셀 높이도 동일하게
빈스토리 보드에 네비게이션 컨트롤러를 추가한다.(테이블 뷰 컨트롤러가 자동으로 추가됨)
테이블뷰 전체를 선택하고 프로토타입 셀 값을 2로 설정 / 셀의 갯수가 2개를 의미한다.
- 텍스트만 있는 셀1, 텍스트+이미지가 있는셀 2개를 만들것
메모작성화면 구성
목록에 BarButton Item을 끌어서 + 버튼을 추가한다.
새로운 뷰컨트롤러를 추가하고 Ctrl + 마우스 드래그하여 세그웨이를 연결한다. 타입은 SHOW
글작성 컨트롤러에 네비게이션 아이템을 추가하고, 타이틀을 글 작성으로 변경한다.
네비게이션바 우측에 BarButtonItem을 추가하고 Title속성을 저장으로 바꾼다. 카메라버튼도 추가
텍스트뷰, 이미지 뷰를 추가한다.
상세화면구성 / 메모목록에서 눌러서 들어간 화면
새로운 뷰컨트롤러를 추가, 목록에서 상세화면으로 이동하는 메뉴얼 세그웨이를 연결한다. > show타입
세그를 클릭하고, Identifier값을 read_sg로 작성(세그웨이 호출 식별값)
화면에 제목과 내용 레이블, 이미지 뷰를 추가한다.
내용 레이블 line값을 0으로 설정 -> 라인수 제약X , LineBreak -> Word Wrap으로 설정
이미지뷰의 높이 값을 선택한다.
세로부분 클릭, 하이트이퀄스 부분 클릭하고 들어가서, 표시부분 체크해준다.
- 이미지 종류에 따라 실제 높이를 변경가능하도록, 높이값은 빌드타임에 제거 되도록 Remove at build time 설정을 추가
네비게이션바에 Navigation item을 추가하고 상세화면으로 변경
커스텀 클래스 생성 및 객체연결
메모 목록화면 클래스 / TextimgListVC.swift
코코아터치 클래스 > UITableVIewController 로 파일 생성
메모목록화면 스토리보드와 TextimgListVC.swift 클래스를 연결한다.
MemoCell클래스를 추가 / UITableViewCell
메모목록화면에서 프로토타입셀을 2개 생성했으므로 두개다 MemoCell클래스를 추가한다.
데이터 모델 작업 - 데이터모델은 사용자가 입력한 데이터를 저장하고, 목록이나 상세화면에 출력할 수 있도록 데이터 소스역할을 하는 객체를 의미한다.
주로 클래스로 정의하며, 여러 속성을 프로퍼티로 정의한다.
// 기능을 구현을 위해 제일먼저 할일 데이터모델을 정의 한다.
// 데이터 소스역할을 하는 객체 생성하기
import UIKit
class MemoData {
var memoIdx : Int? // 데이터 식별값
var title : String? // 메모제목
var contents : String? // 메모내용
var image: UIImage? // 이미지
var regdate: Date? // 작성일
}
AppDelegate.swift파일을 열고 , MemoData타입의 배열변수 memolist를 프로퍼티로 정의한다.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var memolist = [MemoData]() // 메모데이터를 저장할 배열변수
MemoData객체를 [MemoData]()배열 변수에 쌓는다.( 일종의 공용 데이터 저장소 , 앱의 여러객체가 참조한다.)
AppDelegate클래스는 전역변수를 저장하기에 적당하다. 이클래스는 앱전체의 라이프사이클을 관리하는 앱 델리게이트 역할을 하기 때문에, 앱내에서 반드시 하나의 인스턴스만 존재하도록 시스템적으로 보장되어있고, 어디서든 쉽게 접근할 수 있다.
앱이 생성될때 함께 생성되었다가, 앱이 소멸할때 함께 소멸된다. 도중에 소멸되거나 생성되지 않는다. 한번 생성되면 앱이 종료되기 전까지는 계속 유지된다. 앱이 사용할 데이터를 저장해두면, 데이터 유실을 걱정하지 않아도 된다. 다만, 앱 종료시에는 사라진다.
메모작성화면 클래스 / MemoFormVC
- 글제목, 내용, 이미지를 카메라버튼을 눌러 갤러리에서 선택하고, 저장
- 저장버튼을 누르면, 글제목,내용,이미지 내용을 AppDelegate에 만든배열에 추가 후, 이전화면으로 돌아감
- 글제목은 글내용을 입력함과 동시에 같은 내용으로 동시에 작성됨
- 내용을 작성하지 않을경우 alert창 생성
- 이미지피커,텍스트 뷰는 델리게이트 패턴기반으로 동작함.
- viewDidLoaddp 버튼 배경이미지, 줄간격 추가함 @@@
- 저장버튼 얼럿창에 이미지추가 @@@
- 화면터치시 네비바 안보이게 하기 추가@@@
import UIKit
class MemoFormVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate , UITextViewDelegate{
var subject: String! // 글제목
@IBOutlet weak var contents: UITextView! // 텍스트작성영역
@IBOutlet weak var preview: UIImageView!// image 미리보기
// 카메라버튼
@IBAction func pick(_ sender: Any) {
// 이미지 피커 인스턴스를 생성한다.
let picker = UIImagePickerController()
picker.delegate = self // 이미지피커컨트롤러 인스턴스의 델리게이트 속성 현재뷰 컨트롤러 인스턴스로설정
picker.allowsEditing = true // 피커이미지편집 허용
// 이미지피커 화면을 표시한다.
self.present(picker, animated: true)
}
// 사용자가 이미지를 선택하면 자동으로 이 메소드가 호출된다.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// 선택된이미지를 미리보기에 출력한다.
self.preview.image = info[.editedImage] as? UIImage
// 이미지 피커 컨트롤러를 닫는다.
picker.dismiss(animated: false)
}
override func viewDidLoad() {
self.contents.delegate = self
// 배경이미지 설정 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
let bgImage = UIImage(named: "memo-background.png")!
self.view.backgroundColor = UIColor(patternImage: bgImage)
//텍스트뷰의 기본 속성
self.contents.layer.borderWidth = 0
self.contents.layer.borderColor = UIColor.clear.cgColor
// 배경 투명한색으로 설정
self.contents.backgroundColor = UIColor.clear
// 텍스트 줄 간격
let style = NSMutableParagraphStyle()
style.lineSpacing = 9
self.contents.attributedText = NSAttributedString(string: "", attributes:[.paragraphStyle:style])
self.contents.text = ""
}
// 사용자가 텍스트뷰에 뭔가 입력을 하면 자동으로 이 메소드 호출
func textViewDidChange(_ textView: UITextView) {
// 내용의 최대 15자리 까지 읽어서 subject변수에 저장한다.
let contents = textView.text as NSString
// 읽어온 내용이 15자리보다 크면, 15까지만 , 그보다 짧을경우 전체내용을 읽어온다.
let length = ((contents.length > 15) ? 15: contents.length)
// 최대 15자리까지의 내용을 subject변수에 저장한다. 이값이 제목이 됨 / substring 원하는범위만 잘라냄
self.subject = contents.substring(with: NSRange(location: 0, length: length))
// 네비게이션 타이틀에 표시한다.
self.navigationItem.title = self.subject
}
// 저장버튼
// 경고창 이미지추가@@@
@IBAction func save(_ sender: Any) {
// 경고창에 사용될 콘텐츠 뷰 컨트롤러 구성 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
let alertV = UIViewController()
let iconImage = UIImage(named: "warning-icon-60")
alertV.view = UIImageView(image: iconImage)
alertV.preferredContentSize = iconImage?.size ?? CGSize.zero
// 1.내용을 입력하지 않았을 경우,경고한다.
guard self.contents.text?.isEmpty == false else {
let alert = UIAlertController(title: nil, message: "내용을 입력해주세요", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
// 경고창이미지추가 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
alert.setValue(alertV, forKey: "contentViewController")
self.present(alert, animated: true)
return
}
// 2.MemoData 객체를 생성하고, 데이터를 담는다.아까만들었던 데이터모델객체
let data = MemoData() //
data.title = self.subject // 제목
data.contents = self.contents.text // 내용
data.image = self.preview.image // 이미지
data.regdate = Date() // 작성시간
// 3.앱델리게이트 객체를 읽어온 다음, 앱델리게이트에 정의한 memolist 배열에 MemoData객체를 추가한다.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.memolist.append(data)
// 4.작성폼화면을 종료하고, 이전화면으로 돌아간다.(popviewController 이전화면으로 가는 메소드)
_ = self.navigationController?.popViewController(animated: true)
}
}
화면터치시 네비바 안보이게 하기 추가@@@
// 화면터치시 네비게이션바 안보이게 하기
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let bar = self.navigationController?.navigationBar
let ts = TimeInterval(0.3)
UIView.animate(withDuration: ts){
bar?.alpha = (bar?.alpha == 0 ? 1 : 0)
}
}
MemoCell클래스
import UIKit
class MemoCell: UITableViewCell {
@IBOutlet weak var subject: UILabel! //글제목
@IBOutlet weak var contents: UILabel!//글내용
@IBOutlet weak var regdate: UILabel! //날짜시간
@IBOutlet weak var img: UIImageView!// 이미지
}
메모 목록화면 클래스 / TextimgListVC.swift
import UIKit
class TextimgListVC: UITableViewController {
//앱 델리게이트 객체의 참조 정보를 읽어온다.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//테이블의 셀 개수를 결정하는 메소드
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = self.appDelegate.memolist.count
return count
}
// 요청하는 행의 정보를 가져옴
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//1.memolist 배열 데이터에서 주어진 행에 맞는 데이터를 꺼낸다.
let row = self.appDelegate.memolist[indexPath.row]
//2.이미지 속성이 비어있을경우, memoCell 혹은 memoCellWithImage 를 사용
let cellId = row.image == nil ? "memoCell" : "memoCellWithImage"
//3.재사용 큐로부터 프로토타입 셀의 인스턴스를 전달받는다.
// let cell = tableView.dequeueReusableCell(withIdentifier: cellId) as! MemoCell
let cell = tableView.dequeueReusableCell(withIdentifier: cellId) as! MemoCell
//4.memoCell의 내용을 구성한다.
cell.subject?.text = row.title
cell.contents?.text = row.contents
cell.img?.image = row.image
//5.Date타입의 날짜를 yyyy-MM-dd HH:mm:ss 포맷에 맞게 변경한다.
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
cell.regdate?.text = formatter.string(from: row.regdate!)
//6.cell 객체를 리턴한다.
return cell
}
//행을 선택했을때 호출되는 메소드
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// memoList 배열에서 선택된 행에 맞는 데이터를 꺼낸다.
let row = self.appDelegate.memolist[indexPath.row]
//상세화면의 인스턴스를 생성한다.
guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "MemoRead") as? MemoReadVC else {
return
}
//값을 전달한 다음,상세화면으로 이동한다.
vc.param = row
self.navigationController?.pushViewController(vc, animated: true)
}
//디바이스 스크린에 뷰 컨트롤러가 나타낼때 마다 호출되는 메소드
override func viewWillAppear(_ animated: Bool) {
//테이블 데이터를 다시 읽어들인다. 이에 따라 행을 구성하는 로직이 다시 실행될 것이다.
self.tableView.reloadData()
}
}
상세화면구성 / 메모목록에서눌러서 들어간 화면 / MemoReadVC.swift
스토리보드 아이디를 MemoRead로 작성
제목, 내용, 이미지 아울렛을 연결해 변수 생성
MemoData 타입의 변수 param을 상단에 정의
import UIKit
class MemoReadVC: UIViewController {
// 콘텐츠 데이터를 저장하는 변수
var param: MemoData?
@IBOutlet weak var subject: UILabel!// 제목
@IBOutlet weak var contents: UILabel! //내용
@IBOutlet weak var img: UIImageView!// 이미지뷰
override func viewDidLoad() {
super.viewDidLoad()
// 제목,내용,이미지를 출력
self.img.image = param?.image
self.subject.text = param?.title
self.contents.text = param?.contents
// 이미지가 왜 안보일까?
print("이미지 : \( String(describing: self.img.image) )")
// 날짜포맷변환
let formatter = DateFormatter()
formatter.dateFormat="dd일 HH:mm분에 작성됨"
let dateString = formatter.string(from: (param?.regdate)!)
//네비게이션 타이틀에 날짜를 표시
self.navigationItem.title = dateString
}
}
TextimgListVC.swift로 돌아가서 TableView(_:didSelectRowAt:)메소드에 작성한다.
//행을 선택했을때 호출되는 메소드
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// memoList 배열에서 선택된 행에 맞는 데이터를 꺼낸다.
let row = self.appDelegate.memolist[indexPath.row]
//상세화면의 인스턴스를 생성한다.
guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "MemoRead") as? MemoReadVC else {
return
}
//값을 전달한 다음,상세화면으로 이동한다.
vc.param = row
self.navigationController?.pushViewController(vc, animated: true)
}
'iOS > 기본편 | 실전편 -꼼꼼한재은씨' 카테고리의 다른 글
UserDefaults (0) | 2022.02.10 |
---|---|
SideBar / SWRevealViewController 라이브러리 사용 (0) | 2022.02.09 |
Stepper 커스텀을 위한 속성추가 ???????????? (0) | 2022.02.05 |
Stepper (스토리보드, code) (0) | 2022.02.05 |
TabBarController 탭바컨트롤러 ???????? (0) | 2022.02.04 |