양시연
- 실행화면
📝 개발 과정
얘는 별다른 코드가 없기 때문에 개발과정을 글로 표현하겠다.
- View Controller 추가
- 추가한 View Controller를 선택한 상태에서 Xcode 상단의 Editor - Embed In - Navigation Controller를 클릭
- 버튼을 추가하고, 이 버튼을 눌렀을 때 이동할 View Controller를 하나 더 추가
- 화면 전환을 push로 설정하면 버튼을 눌렀을 때 화면 전환이 일어난다!
- 실행화면
📝 개발 과정
- LoginViewController
HomeViewController에서 이메일과 비밀번호를 화면에 띄워줘야 하기 때문에 emailTextField의 값과 passwordTextField의 값을 전달한다. 그리고 LoginVC -> HomeVC는 present 형태로 전환을 하기 때문에 코드로 전환해주고, LoginVC -> SignupVC는 push 형태로 전환을 하기 때문에 스토리 보드상에서 간단하게 전환을 설정해 줄 수 있다.
@IBAction func trasferData(_ sender: Any) {
guard let receiveViewController = self.storyboard?.instantiateViewController(identifier: "homeViewController") as? HomeViewController else { return }
receiveViewController.email = emailTextField.text
receiveViewController.password = passwordTextField.text
receiveViewController.modalPresentationStyle = .fullScreen
self.present(receiveViewController, animated: true, completion: nil)
}
- SignupViewController
LoginViewController의 transferData와 똑같다. (근데 왜 두개 이름을 이렇게 지었지? 함수명 짓는 규칙도 생각해봐야겠다.)
@IBAction func didTouchSignupComplete(_ sender: Any) {
guard let receiveViewController = self.storyboard?.instantiateViewController(identifier: "homeViewController") as? HomeViewController else { return }
receiveViewController.email = emailTextField.text
receiveViewController.password = passwordTextField.text
receiveViewController.modalPresentationStyle = .fullScreen
self.present(receiveViewController, animated: true, completion: nil)
}
- HomeViewController
setLabels()라는 함수에서 다른 ViewController에서 받아온 email과 password 라벨의 값을 초기화 시켜준다.
var email: String?
var password: String?
private func setLabels(){
// Optional Binding
// guard let은 optional을 깨서 확인을 하려고 하는 것
guard let email = self.email else { return }
guard let password = self.password else { return }
// Label에 값 대입
emailLabel.text = email
passwordLabel.text = password
}
또한, 아래와 같은 코드로 로그아웃 버튼을 누르면 LoginVC로 이동시켜준다.
@IBAction func backScreen(_ sender: Any) {
let navigationController = self.presentingViewController as? UINavigationController
self.dismiss(animated: true) {
let _ = navigationController?.popToRootViewController(animated: true)
}
}
- 실행화면
📝 개발 과정
- 1개의 Vertical Stack View를 만들고, 그 안에 4개의 Horizontal Stack View를 집어 넣는다.
- 여기서 쓰이는 Stack View는 모두 안의 버튼이 같은 크기를 가지고 있고, 같은 간격으로 띄워져 있기 때문에 distribution을 fill equally로 준다.
- spacing을 적당히 준다.
- 버튼이 정사각형이 되게 하려면 spacing을 잘 고려해서 Vertical Stack View의 height를 설정해주어야 한다.
- 버튼에 radius를 주기 위해서 다음과 같은 코드를 작성한다.
acBtn.layer.cornerRadius = 0.5 * acBtn.bounds.size.width
- 실행화면
📝 개발 과정
- Scroll View를 추가해준다.
- Scroll View 안에 콘텐츠들을 담을 View를 추가하고, Scroll View의 Content Layout Guide에 constraint 값을 준다. (콘텐츠를 담을 View는 주로 Content View라고 부르는 것 같다.)
- 이 화면은 세로로 스크롤 되므로 Scroll View의 Frame Layout Guide의 Width를 Conent View의 width와 같게 해준다.
- Image View를 추가하고, 아래의 콘텐츠들은 계산기 과제와 똑같이 Stack View와 CornerRadius를 이용해서 구현한다.
- 아래 콘텐츠를 다 구현했으면 Scroll View 바로 밑의 View에 23의 constraint값을 주면서 Scroll View의 크기를 알려준다. (중요⭐️)
- 실행화면
📝 개발 과정
- 먼저 View Controller를 생성하고 Tab Bar Controller를 Embed in 또는 relationship segue 시켜준다.
- 똑똑한 Xcode가 알아서 탭바를 만들어주면 ViewController의 Tab Bar Item에서 선택되었을 때 이미지와 기본 이미지(선택 안되었을 때 이미지)를 선택해준다.
- 기본적으로 제공되는 이미지를 이용하면 색이 파란색이다. 이때, Tab Bar Item의 색상을 바꿔주기 위해서는 Tab Bar Controller에서 Image Tint 색상을 바꿔주어야 한다.
다른 iOS 파트원들은 제일 상단의 내 정보 부분을 섹션을 나눠서 또 다른 Table View Cell로 처리했던데,, 안드로이드에 익숙해서 그런지 그런 생각을 전!혀! 하지 못했다. "어차피 하나 나오는 뷰니까~ 고냥 View로 감싸서 박자~" 라고 생각했다. 나 자신 반성,, 그래서 뷰 구조가 아래와 같다.
📝 개발 과정
- 스토리보드에 뷰를 그린다.
- ViewController에 FriendListViewController.swift 파일을 연결한다. 이 소스코드에서 중요한 부분은 다음과 같다.
👉 데이터를 뿌려주기 위해서 더미 데이터 리스트를 만들고 viewDidLoad() 함수에서 불러준다. (하드코딩된 부분이 많으므로 생략!) 👉 Table View의 이벤트를 대신 처리해 줄 객체를 지정한다.
override func viewDidLoad() {
super.viewDidLoad()
setFriendList()
friendTableView.delegate = self
friendTableView.dataSource = self
}
👉 Table View에 들어갈 값에 대한 정의와 이벤트를 아래와 같이 구현한다.
각 함수가 하는 일은 위에서 부터 차례대로 Table Cell의 개수 return, Table Cell 설정, Table Cell 1개의 높이 지정 이다.
extension FriendListViewController : UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friendsList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let friendCell = tableView.dequeueReusableCell(withIdentifier: FriendCell.identifier, for: indexPath) as? FriendCell else {return UITableViewCell()}
friendCell.setFriend(image: friendsList[indexPath.row].profileImage, name: friendsList[indexPath.row].userName, message: friendsList[indexPath.row].message)
return friendCell
}
}
extension FriendListViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 62
}
}
- 자 바로 위 코드에 있는 friendCell이란 무엇인가! 바로 Table View Cell에 대한 설정을 하기 위해 소스코드가 하나 더 필요하다. 나는 FriendCell.swift 라는 이름으로 파일을 하나 만들어 주었다.
👉 스토리보드에서 Table View Cell을 선택하고 Custom Class로 FriendCell을 지정해준다.
👉 또한 Identifier도 설정해준다.
👉 FriendCell.swift에서는 Table View Cell의 아울렛들을 가져와서 이름을 지어주고, 이들을 설정하는 코드를 작성해준다.
import UIKit
class FriendCell: UITableViewCell {
static let identifier: String = "FriendCell"
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var messageLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setFriend(image: String, name: String, message: String?){
profileImageView.image = UIImage(named: image)
nameLabel.text = name
messageLabel.text = message
}
}
도전 과제 치고는 생각보다 쉽게 해결할 수 있었다.
📝 개발 과정 Table View에 들어갈 값에 대한 정의를 해주는 extension 객체에 다음과 같은 일을 추가한다.
- 우선 canEditRowAt이 들어있는 함수에서 true를 반환하여 row를 편집할 수 있도록 한다.
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
- 아래와 같은 함수로 tableView를 edit할 때 일어나는 일을 구현한다.
해당 코드는 tableView에서 삭제가 일어날 때 tableView에 뿌려지는 friendList에서 삭제할 데이터를 없애고 tableView를 업데이트하는 코드이다. tableView 업데이트 후엔 상단에 위치한 친구의 수를 나타낸 label의 text를 friendList의 사이즈로 바꿔준다.
💡 가장아래에 있는 tableView.reloadData()를 이용하면 위에서 어떤 일을 한 다음에 tableView를 새로 로드해서 뷰가 새로 그려지게 된다. 하지만 이 코드를 사용하면 그냥 뷰가 다시 그려지는 것이기 때문에 내가 삭제한 셀이 없어진건지 파악하기가 어렵고, 개인적으로 iOS의 장점이라고 생각하는 예쁜 애니메이션도 없다. 그래서 구글링을 통해 더 찾아본 결과 deleteRows()라는 함수를 사용하면 실제로 tableView의 indexPath에 위치한 row를 지웠다고 알려주고 이에 맞는 애니메이션도 예쁘게 생긴다! (ㅎㅎ 뿌듯)
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if(editingStyle == .delete){
// friendList에서 해당 data 삭제 후 table view 업데이트
friendsList.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
friendCountLabel.text = "친구 \(friendsList.count)"
// tableView.reloadData()
}
}
📝 개발 과정
- 세팅 버튼을 클릭 IBAction 함수를 만든다.
- UIAlertController 객체를 만들고 preferredStyle은 actionSheet로 지정해준다.
- UIAlertAction 객체를 만들어주고 UIAlertController에 달아준다.
- UIAlertController를 present로 띄워준다!
💡 밑에서 올라오는 애는 Action Sheet이고 가운데에 빡 뜨는 애는 Alert이다. Alert 형태로 띄우고 싶으면 preferredStyle을 alert로 지정해주면 된다. alert는 말그대로 경고창 같은 것이기 때문에 선택지가 1개인 경우에 주로 사용한다!
@IBAction func touchSettingBtn(_ sender: UIButton) {
let settingMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let manageFriendAcition = UIAlertAction(title:"친구 관리", style: .default, handler:{ (alert: UIAlertAction!) -> Void in
})
let settingAllAcition = UIAlertAction(title:"전체 설정", style: .default, handler:{
(alert: UIAlertAction!) -> Void in
})
let cancleAction = UIAlertAction(title:"취소", style: .cancel, handler:{
(alert: UIAlertAction!) -> Void in
})
settingMenu.addAction(manageFriendAcition)
settingMenu.addAction(settingAllAcition)
settingMenu.addAction(cancleAction)
self.present(settingMenu, animated: true, completion: nil)
}