iOS/UIKIT

테이블 만들기

밤새는 탐험가89 2024. 1. 21. 11:44

 

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

 

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

 

 

 

 

테이블 뷰 변수 선언, 제약조건, 뷰 등록 ->

테이블 셀에 들어갈 데이터 뼈대 및 뼈대를 통해 얻은 데이터를 관리할 모델 생성 

-> 테이블 셀 안에 들어갈 UI 설정 -> 테이블뷰와 테이블 셀 연결 및 데이터 전달 

 

 

ViewController.swift

import UIKit

class ViewController: UIViewController {
    
    // 11. DataManager 클래스의 인스턴스 생성
    var fruitDataManager = DataManager()
    
    // 12. 생선된 fruitDataManager 인스턴스를 통해 받아온 데이터를 담을 배열 선언
    var fruitArray: [Fruit] = []
    
    
    // 1. 테이블 뷰 변수 선언
    private let tableView: UITableView = {
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 3. 뷰에 tableView 올림
        view.addSubview(tableView)
        
        // 4. 제약 조건 올림 (이 뒤로 Model 폴더 명 내에 Fruit, DataManager 파일 생성)
        tableViewConfigureConstraints()
        
        
        // 16. DataManager에게 데이터 생성을 요청 및 받아온 데이터를 배열에 할당
        fruitDataManager.makeFruitDatasArray()
        fruitArray = fruitDataManager.getFruitDatasArray()
        
        // 17. 테이블셀 높이 설정
        tableView.rowHeight = 120
        
        // 14. dataSource의 대리자 선언
        tableView.dataSource = self
        
        // 15. 테이블 뷰 등록
        tableView.register(ContentsTableViewCell.self, forCellReuseIdentifier: "cell")
    }
    
    // 2. 테이블 뷰 관련 제약 조건 설정
    private func tableViewConfigureConstraints() {
        
        let tableViewConstraints = [
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ]
        NSLayoutConstraint.activate(tableViewConstraints)
    }
}


// 13. 전달 받은 데이터를 통해 테이블을 구성하기 위해 UITableViewDataSource 프로토콜 채택
extension ViewController: UITableViewDataSource {
    
    // 행의 수 설정
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return fruitArray.count
    }
    
    
    // 데이터를 테이블 셀에 각각 설정
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ContentsTableViewCell
        
        cell.fruitImageView.image = fruitArray[indexPath.row].fruitImage
        cell.fruitNameLabel.text = fruitArray[indexPath.row].fruitName
        cell.fruitDescriptionLabel.text = fruitArray[indexPath.row].fruitDescription
        
        cell.selectionStyle = .none
        
        return cell
    }
}

 

 

여기서 중요한 부분은 대리자 선언및 테이블뷰 등록

 

 

Model 폴더 내에 두 데이터 관련 파일 생성

 

 

Fruit 파일 내에 아래 코드 작성

// 5. 데이터 모델 구조 생성 (이를 통해 데이터 뼈대 생성 -> DataManager 파일로 넘어갈 것)
struct Fruit {
    var fruitImage: UIImage?
    var fruitName: String
    var fruitDescription: String
    
}

 

DataManager 파일 내에 아래 코드 작성

// 6. Fruit의 데이터 뼈대를 기준으로 데이터 관리 모델 생성
class DataManager {
    
    private var fruitDataArray: [Fruit] = []
    
    // 7. 데이터를 저장할 배열을 생성 하고,
    // 이를 통해 CRUD 할 함수를 따로 생성 할 것 (Views 폴더 내에 ContentsTableViewCell 파일 생성)
    func makeFruitDatasArray() {
        
        fruitDataArray = [
            Fruit(fruitImage: UIImage(named: "avocado"), fruitName: "avocado", fruitDescription: "과일의 일종으로 원산지는 멕시코를 비롯한 중남미 지역. 멕시코에서는 연중 재배 및 수출이 가능하며, 현지 도매시장에서는 가격이 매우 저렴한 편이다."),
            Fruit(fruitImage: UIImage(named: "blueberry"), fruitName: "blueberry", fruitDescription: "북아메리카를 비롯한 북반구 전역에 분포하는 식물 및 열매. 이름과 달리 딸기, 라즈베리, 블랙베리 등의 베리류와는 전혀 관계가 없는 진달래과 식물[1]이다. 꽃말은 현명과 친절이다."),
            Fruit(fruitImage: UIImage(named: "cherry"), fruitName: "cherry", fruitDescription: "벚나무의 열매. 순우리말로는 버찌라고 한다. 다만 보통 한국에서 접하는 사진의 서양버찌는 체리라 부르고 동양버찌는 버찌라고 별개로 부르는 편이 많다."),
            Fruit(fruitImage: UIImage(named: "avocado"), fruitName: "avocado", fruitDescription: "과일의 일종으로 원산지는 멕시코를 비롯한 중남미 지역. 멕시코에서는 연중 재배 및 수출이 가능하며, 현지 도매시장에서는 가격이 매우 저렴한 편이다."),
            Fruit(fruitImage: UIImage(named: "blueberry"), fruitName: "blueberry", fruitDescription: "북아메리카를 비롯한 북반구 전역에 분포하는 식물 및 열매. 이름과 달리 딸기, 라즈베리, 블랙베리 등의 베리류와는 전혀 관계가 없는 진달래과 식물[1]이다. 꽃말은 현명과 친절이다."),
            Fruit(fruitImage: UIImage(named: "cherry"), fruitName: "cherry", fruitDescription: "벚나무의 열매. 순우리말로는 버찌라고 한다. 다만 보통 한국에서 접하는 사진의 서양버찌는 체리라 부르고 동양버찌는 버찌라고 별개로 부르는 편이 많다."),
            Fruit(fruitImage: UIImage(named: "avocado"), fruitName: "avocado", fruitDescription: "과일의 일종으로 원산지는 멕시코를 비롯한 중남미 지역. 멕시코에서는 연중 재배 및 수출이 가능하며, 현지 도매시장에서는 가격이 매우 저렴한 편이다."),
            Fruit(fruitImage: UIImage(named: "blueberry"), fruitName: "blueberry", fruitDescription: "북아메리카를 비롯한 북반구 전역에 분포하는 식물 및 열매. 이름과 달리 딸기, 라즈베리, 블랙베리 등의 베리류와는 전혀 관계가 없는 진달래과 식물[1]이다. 꽃말은 현명과 친절이다."),
            Fruit(fruitImage: UIImage(named: "cherry"), fruitName: "cherry", fruitDescription: "벚나무의 열매. 순우리말로는 버찌라고 한다. 다만 보통 한국에서 접하는 사진의 서양버찌는 체리라 부르고 동양버찌는 버찌라고 별개로 부르는 편이 많다.")
        ]
    }
    
    func getFruitDatasArray() -> [Fruit] {
        return fruitDataArray
    }
    
}

 

 

테이블 셀 관련 파일 생성

 

 

생성한 ContentsTableViewCell 파일 내 아래 코드 작성

import UIKit

class ContentsTableViewCell: UITableViewCell {
    
    // 8. 테이블 셀 안에 들어갈 라벨과 이미지 구현
    let fruitImageView: UIImageView = {
        let imageView = UIImageView(image: UIImage.banana)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.layer.masksToBounds = true
        imageView.layer.cornerRadius = 5
        return imageView
    }()
    
    let fruitNameLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "바나나"
        label.font = .systemFont(ofSize: 22, weight: .bold)
        label.textColor = .black
        return label
    }()
    
    let fruitDescriptionLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 15, weight: .regular)
        label.textColor = .black
        label.numberOfLines = 2
        label.text = "바나나는 생강목 파초과 파초속에 속하는 외떡잎식물의 총칭으로, 흔히 열매만을 가리키기도 한다."
        return label
    }()
    
    private let stackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .fill
        stackView.alignment = .fill
        stackView.spacing = 15
        return stackView
    }()
    
    // 9. 테이블 셀에 필요한 내용을 업데이트
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: .default, reuseIdentifier: reuseIdentifier)
        
        self.contentView.addSubview(fruitImageView)
        self.contentView.addSubview(stackView)
        stackView.addArrangedSubview(fruitNameLabel)
        stackView.addArrangedSubview(fruitDescriptionLabel)
        
        configureConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    // 10. 테이블 셀 안에 라벨과 이미지 관련 제약 조건 설정 (ViewController 파일로 넘어갈 것)
    private func configureConstraints() {
        
        let fruitImageViewConstraints = [
            fruitImageView.heightAnchor.constraint(equalToConstant: 100),
            fruitImageView.widthAnchor.constraint(equalToConstant: 100),
            fruitImageView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10),
            fruitImageView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 10)
        ]
        
        let fruitNameLabelConstraints = [
            fruitNameLabel.heightAnchor.constraint(equalToConstant: 22)
        ]
        
        let stackViewConstraints = [
            stackView.leadingAnchor.constraint(equalTo: fruitImageView.trailingAnchor, constant: 10),
            stackView.topAnchor.constraint(equalTo: fruitImageView.topAnchor, constant: 5),
            stackView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -10)
        ]
        
        NSLayoutConstraint.activate(fruitImageViewConstraints)
        NSLayoutConstraint.activate(fruitNameLabelConstraints)
        NSLayoutConstraint.activate(stackViewConstraints)
    }
}

 

 

다시 ViewController 파일로 돌아와서 아래 코드 작성

 

 

 

몇 가지 확인해봐야 하는 상황

왜 테이블뷰셀에서는 init 함수를 사용하는가?

여기다가 데이터를 생성 읽기 업데이트 쓰기를 네비게이션바를 통해 해볼 것 

셀을 누르면 디테일 화면으로는 어떻게 넘어가는가?