본문 바로가기
스파르타코딩 클럽/개인과제

22. 스파르타 코딩클럽 [본캠프 - 포켓몬 연락처앱 (1)]

by UDDT 2025. 4. 17.



Ch 4. 앱 개발 숙련 주차 과제

 

 포켓몬 연락처 앱 만들기

 

     - Lv.1

- 캡처된 모습과 같게 UI 를 구현합니다.

UILabel, UITableView, UIButton 을 이용해서 기본적인 UI 를 구성합니다.
UITableViewCell 에는 프로필 이미지를 보여줄 UIImageView 와 이름을 보여줄 UILabel 을 넣습니다.
전화번호를 표시할 UILabel 도 넣습니다.
프로필 이미지는 원모양이 되도록 합니다.
“추가” 버튼을 우상단에 위치 시킵니다.
Cell 의 높이는 80으로 지정합니다.

* 원의 테두리는 layer.borderColor, layer.borderWidth 개념을 사용하면 구현할 수 있습니다.
캡처된 화면은 임의의(더미) dataSource 를 끼워넣어 UI 를 확인한 모습입니다. 

 

     - 내가 작성한 코드

// ViewController.swift
class ViewController: UIViewController {

    // UILabel 생성
    private let label: UILabel = {
        let label = UILabel()
        label.text = "친구 목록"
        label.textColor = .black
        label.font = .boldSystemFont(ofSize: 30)
        label.textAlignment = .center
        return label
    }()

    // button이 탭되었을 때, self를 작성하려면 lazy var로 선언되어 있어야함
    private lazy var button: UIButton = {
        let button = UIButton()
        button.setTitle("추가", for: .normal)
        button.setTitleColor(.gray, for: .normal)
        button.backgroundColor = .white
//        button.addTarget(self, action: <#T##Selector#>, for: <#T##UIControl.Event#>)
        return button
    }()

    // TableView 생성
    private let tableView: UITableView = {
        let tableView = UITableView()
        // register로 셀을 등록해줘야 셀이 화면에 표시됨
        tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.id)
        return tableView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        configureUI()
        //tableView의 delegate와 dataSource가 VC임을 명시해야함
        tableView.delegate = self
        tableView.dataSource = self
    }

    func configureUI() {
        view.backgroundColor = .white
        [label, button, tableView].forEach { view.addSubview($0) }

        label.snp.makeConstraints {
            $0.top.equalToSuperview().offset(70)
            $0.centerX.equalToSuperview()
        }

        button.snp.makeConstraints {
            $0.centerY.equalTo(label.snp.centerY)
            $0.trailing.equalToSuperview().offset(-20)
        }

        tableView.snp.makeConstraints {
            $0.centerX.equalToSuperview()
            $0.top.equalTo(label.snp.bottom).offset(40)
            $0.bottom.equalToSuperview().offset(-50)
            $0.leading.trailing.equalToSuperview().inset(30)
        }
    }

}

// TableView의 Delegate
extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        80
    }
}

// TableView의 DataSource
extension ViewController: UITableViewDataSource {

    // 셀을 return하려면 셀을 만들어야 함
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 여기서 재사용이 가능한 셀을 만들어줌
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.id) as? TableViewCell else { return UITableViewCell() }
        return cell
    }
    
    // 섹션 안에 있는 행의 개수
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        7
    }
}
// TableViewCell.swift
class TableViewCell: UITableViewCell {

    // 이게 셀을 식별하는 고유 ID, 나중에 재사용할 때 어떤 셀인지 넣어줘야 함
    static let id = "TableViewCell"

    let nameLabel: UILabel = {
        let label = UILabel()
        label.text = "name"
        label.textColor = .black
        label.font = .systemFont(ofSize: 14)
        return label
    }()

    let phoneNumberLabel: UILabel = {
        let label = UILabel()
        label.text = "010-0000-0000"
        label.textColor = .black
        label.font = .systemFont(ofSize: 14)
        return label
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        configureUI()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func configureUI() {
        let imageView: UIImageView = {
            let imageView = UIImageView()
            imageView.image = UIImage(named: "")
            imageView.contentMode = .scaleAspectFit
            imageView.layer.cornerRadius = 30
            imageView.layer.borderWidth = 1
            return imageView
        }()

        // 셀 안에 view를 반영할 때는 contentView에 반영해주면 됨
        [imageView, nameLabel, phoneNumberLabel].forEach { contentView.addSubview($0) }

        imageView.snp.makeConstraints {
            $0.centerY.equalTo(contentView.snp.centerY)
            $0.width.height.equalTo(60)
            $0.leading.equalTo(contentView.snp.leading).offset(20)
        }

        nameLabel.snp.makeConstraints {
            $0.centerY.equalTo(imageView.snp.centerY)
            $0.leading.equalTo(imageView.snp.trailing).offset(20)
        }

        phoneNumberLabel.snp.makeConstraints {
            $0.centerY.equalTo(imageView.snp.centerY)
            $0.trailing.equalTo(contentView.snp.trailing).offset(-20)
        }

    }

}

 

 UITableView

    https://developer.apple.com/documentation/uikit/uitableview

 

UITableView | Apple Developer Documentation

A view that presents data using rows in a single column.

developer.apple.com

 

 

 테이블뷰는 위의 사진과 같이 반복되는 행을 표현할 때 효과적이다

테이블뷰의 각각의 행에는 cell이라는 객체가 존재하고, 

그 객체를 세팅해서 테이블 위에 얹을 수 있다.

 

  TableView를 사용하려고 할 때, 반드시 알아야하는 개념은 

 TableViewCell, TableViewDataSource, TableViewDelegate이다

 

  - TableViewCell

    https://developer.apple.com/documentation/uikit/uitableviewcell

 

UITableViewCell | Apple Developer Documentation

The visual representation of a single row in a table view.

developer.apple.com

   TableViewCell은 테이블뷰에서 단일 행을 나타내는 시각적인 부분이다.

 

   다음의 그림에서 볼 수 있듯 TableViewCell은 Content 영역(ContentView)을 가지고 있으며,

  해당 영역을 커스터마이징할 수 있다.

   

   첫번째 그림에서처럼 셀에 선택 영역이나 강조 색상을 적용하게 할 수 있고,

   두번째 그림에서처럼 보조 뷰(Detail 등)를 추가할 수도 있다.

   세번째 그림에서처럼 셀을 삭제하는 등의 편집이 가능한 상태로 만들 수도 있다.

 

 
  - TableVieDelegate

    https://developer.apple.com/documentation/uikit/uitableviewdelegate

 

UITableViewDelegate | Apple Developer Documentation

Methods for managing selections, configuring section headers and footers, deleting and reordering cells, and performing other actions in a table view.

developer.apple.com

 

     TableViewDelegate의 내부에도 다양한 기능이 있지만, 그 중 가장 기본적으로 사용되는 기능은

   행의 높이를 정해주는 기능이다.

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        70
    }
}

 

     위의 코드처럼 높이를 설정해줄 수 있는데,

   앞서 설명한 것들과 마찬가지로 행의 높이를 지정해줘야 TableView를 이상 없이 구현할 수 있다.

 

  - TableViewDataSource

      테이블뷰 셀의 ContentView에 무언가를 채워넣었다고 끝나는 것이 아니다.

     테이블뷰 설정을 위해서는 UITableViewDataSource 프로토콜을 채택하고,

     필수 메서드를 구현해줘야 한다.

extension ViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as? TableViewCell else {
            return UITableViewCell()
        }
        return cell
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        7
    }

}

 

   numberOfRowsInSection은 섹션에 행을 몇개 설정할 것인지,

   cellForRowAt은 행에 표시할 셀이 무엇인지 세팅하는 것이다.

 

   여기서 중요한 것이 cell을 식별하는 Identifier이다.

  Identifier를 통해 어떤 클래스의 TableViewCell을 적용할 것인지 식별할 수 있기 때문에,

  해당 부분을 누락(혹은 잘못 작성)하면 원하는 데이터를 전달하지 못하는 경우가 있기 때문에 주의하도록 하자.

 

 UITableView에 데이터 채우기

    https://developer.apple.com/documentation/uikit/filling-a-table-with-data

 

Filling a table with data | Apple Developer Documentation

Create and configure cells for your table dynamically using a data source object, or provide them statically from your storyboard.

developer.apple.com

 

최근댓글

최근글

skin by © 2024 ttuttak