iOS_ TableView(2)

longlivedrgn·2022년 11월 15일
0

iOS 스터디

목록 보기
7/8
post-thumbnail

Custom Cell

  • 아래와 같이 tableview와 cell을 만들어준다. 그리고 delegate과 datasource를 연결해준다.

  • 아래와 같이 tableview를 설정해준다.

import UIKit


class CustomCellViewController: UIViewController {
    
    let list = WorldTime.generateData()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
}




extension CustomCellViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        let target = list[indexPath.row]
        cell.textLabel?.text = target.location
        cell.detailTextLabel?.text = "\(target.date) \(target.time)"
        
        return cell
    }
}
  • WorldTime의 아래와 같다.
import Foundation

struct WorldTime {
    let date: String
    let hoursFromGMT: Int
    let location: String
    let ampm: String
    let time: String
    
    static func generateData() -> [WorldTime] {
        let list = [("Asia/Seoul", "서울"), ("America/New_York", "뉴욕"), ("Europe/Paris", "파리"), ("Europe/London", "런던"), ("Europe/Zurich", "취리히")]
        
        let now = Date()
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "Ko_kr")
        formatter.doesRelativeDateFormatting = true
        
        var result = [WorldTime]()
        
        for (timeZone, location) in list {
            guard let tz = TimeZone(identifier: timeZone) else { continue }
            
            let dt = now.addingTimeInterval(TimeInterval(tz.secondsFromGMT() - (9 * 3600)))
            
            formatter.dateStyle = .short
            formatter.timeStyle = .none
            let date = formatter.string(from: dt)
            
            formatter.dateFormat = "a"
            let ampm = formatter.string(from: dt)
            
            formatter.dateFormat = "h:mm"
            let time = formatter.string(from: dt)
            let hoursFromGMT = (tz.secondsFromGMT() / 3600) - 9
            
            let data = WorldTime(date: date, hoursFromGMT: hoursFromGMT, location: location, ampm: ampm, time: time)
            result.append(data)
        }
        
        return result
    }
}
  • tableview 한개의 cell의 height를 설정해줄 수 있다.

  • 새로운 cell을 추가해주고(customCell로 identifier를 설정해준다), 새로운 Cell에 stackview 두 개를 넣어준다.

  • 그리고 새로운 cell에 있는 각각의 label에 tag를 100,200,300,400으로 설정해준다.

  • 그리고 원래 viewcontroller의 datasource를 아래와 같이 설정할 수 있다.

extension CustomCellViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath)
        
        let target = list[indexPath.row]
        
        if let dataLabel = cell.viewWithTag(100) as? UILabel{
            dataLabel.text = "\(target.date), \(target.hoursFromGMT)시간"
        }
        if let locationLabel = cell.viewWithTag(200) as? UILabel{
            locationLabel.text = target.location
        }
        if let ampmLabel = cell.viewWithTag(300) as? UILabel{
            ampmLabel.text = target.ampm
        }
        if let timeLabel = cell.viewWithTag(400) as? UILabel{
            timeLabel.text = target.time
            
        }
        
        return cell
    }
}
  • 최종적으로 아래와 같이 view를 구성할 수 있다.

CustomCell을 만드는 새로운 방법

  • CocoaTouch로 새로운 tableviewcell(TImeTableViewCell)을 만들어준다.

  • 그리고 새로운 cell에 Class timetableviewcell을 넣어준다.

  • 그리고 TImeTableViewCell에 label들의 Outlet을 설정해준다.

import UIKit

class TImeTableViewCell: UITableViewCell {

    @IBOutlet weak var timeLabel: UILabel!
    @IBOutlet weak var ampmLabel: UILabel!
    @IBOutlet weak var locationLabel: UILabel!
    @IBOutlet weak var dateLabel: 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
    }

}
  • 아래와 같이 TimeTableViewCell로 downcasting해서 deque를 하고 cell의 데이터를 설정해준다.
extension CustomCellViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // DownCasting을 해줘야된다.
        let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TImeTableViewCell

        let target = list[indexPath.row]
        
        cell.dateLabel.text = "\(target.date), \(target.hoursFromGMT)시간"
        cell.locationLabel.text = target.location
        cell.ampmLabel.text = target.ampm
        cell.timeLabel.text = target.time
        
        

//
//        if let dataLabel = cell.viewWithTag(100) as? UILabel{
//            dataLabel.text = "\(target.date), \(target.hoursFromGMT)시간"
//        }
//        if let locationLabel = cell.viewWithTag(200) as? UILabel{
//            locationLabel.text = target.location
//        }
//        if let ampmLabel = cell.viewWithTag(300) as? UILabel{
//            ampmLabel.text = target.ampm
//        }
//        if let timeLabel = cell.viewWithTag(400) as? UILabel{
//            timeLabel.text = target.time
//
//        }
        return cell
    }
}

Customizing Section

  • 아래와 같이 Region 코드를 준비한다.
import Foundation

class Region {
    let title: String
    var countries: [String]
    
    init(title: String, countries: [String]) {
        self.title = title
        self.countries = countries
    }
    
    static func generateData() -> [Region] {
        var list = [Region]()
        let localeList = [Locale(identifier: "en_US"), Locale(identifier: "ko_KR")]
        
        for l in localeList {
            for id in Locale.isoRegionCodes {
                guard let name = l.localizedString(forRegionCode: id) else {
                    continue
                }
                
                guard let chosung = name.chosung else {
                    continue
                }
                
                let region = list.first { $0.title.compare(chosung, options: .diacriticInsensitive) == .orderedSame }
                
                if let region = region {
                    region.countries.append(name)
                } else {
                    list.append(Region(title: chosung, countries: [name]))
                }
            }
        }
        
        for item in list {
            item.countries.sort()
        }
        
        list.sort(by: { $0.title < $1.title } )
        
        return list
    }
}

extension String {
    private var koreanUnicodeRange: (Int, Int) {
        return (0xAC00, 0xD7AF)
    }
    
    var chosung: String? {
        guard utf16.count > 0 else {
            return nil
        }
        
        let chosungList = ["ㄱ","ㄲ","ㄴ","ㄷ","ㄸ","ㄹ","ㅁ","ㅂ","ㅃ","ㅅ","ㅆ","ㅇ","ㅈ","ㅉ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"]
        let code = utf16[utf16.startIndex]
        
        if code >= UInt16(koreanUnicodeRange.0) && code <= UInt16(koreanUnicodeRange.1) {
            let unicode = code - UInt16(koreanUnicodeRange.0)
            let chosungIndex = Int(unicode / 21 / 28)
            return chosungList[chosungIndex]
        }
        
        return String(first!)
    }
}
  • 아래와 같이 tableview와 tableviewcell을 생성한다.
  • 아래와 같이 tableview의 datasource를 구성해준다.
import UIKit

class SectionHeaderAndFooterViewController: UIViewController {
    
    @IBOutlet weak var listTableView: UITableView!
    
    let list = Region.generateData()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
}



extension SectionHeaderAndFooterViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return list.count
    }
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list[section].countries.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        let target = list[indexPath.section].countries[indexPath.row]
        cell.textLabel?.text = target
        
        return cell
    }
}




extension SectionHeaderAndFooterViewController: UITableViewDelegate {
    
}
  • 그리고 마지막에 sectionHeader에 데이터의 title이 표시가 되도록 코드를 추가해주자.
extension SectionHeaderAndFooterViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return list.count
    }
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list[section].countries.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        let target = list[indexPath.section].countries[indexPath.row]
        cell.textLabel?.text = target
        
        return cell
    }
    
    // sectionHeader에 title이 표시되게해보자.
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return list[section].title
    }
}
  • 그러면 아래와 같이 sectionheader가 생성이된다.

Custom Section을 만들어보자

  • listTableview에 headerfooterview를 넣어준다.(identifier가 'header')
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        listTableView.register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "header")
        
    }
  • 위에서 등록해준 headerfooterview를 customizing해서 생성해준다.
extension SectionHeaderAndFooterViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerview = tableView.dequeueReusableCell(withIdentifier: "header")
        headerview?.textLabel?.text = list[section].title
        headerview?.detailTextLabel?.text = "lorem ipsum"

        return headerview
    }
    
    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        if let headerview = view as? UITableViewHeaderFooterView {
            headerview.textLabel?.textColor = .systemBlue
            headerview.textLabel?.textAlignment = .center
            
            // backgroundcolor 설정하기
            if headerview.backgroundView == nil {
                let v = UIView(frame: .zero)
                v.backgroundColor = .secondarySystemFill
                v.isUserInteractionEnabled = false
                headerview.backgroundView = v
            }
        }
    }
}
  • 그러면 최종적으로 아래와 같이 custom된 sectionheader를 만들 수 있다.

Section Index Titles

  • 아래와 같이 view를 만들고 datasource delegate을 설정해준다.

  • Region 코드를 사용한다.

import Foundation

class Region {
    let title: String
    var countries: [String]
    
    init(title: String, countries: [String]) {
        self.title = title
        self.countries = countries
    }
    
    static func generateData() -> [Region] {
        var list = [Region]()
        let localeList = [Locale(identifier: "en_US"), Locale(identifier: "ko_KR")]
        
        for l in localeList {
            for id in Locale.isoRegionCodes {
                guard let name = l.localizedString(forRegionCode: id) else {
                    continue
                }
                
                guard let chosung = name.chosung else {
                    continue
                }
                
                let region = list.first { $0.title.compare(chosung, options: .diacriticInsensitive) == .orderedSame }
                
                if let region = region {
                    region.countries.append(name)
                } else {
                    list.append(Region(title: chosung, countries: [name]))
                }
            }
        }
        
        for item in list {
            item.countries.sort()
        }
        
        list.sort(by: { $0.title < $1.title } )
        
        return list
    }
}

extension String {
    private var koreanUnicodeRange: (Int, Int) {
        return (0xAC00, 0xD7AF)
    }
    
    var chosung: String? {
        guard utf16.count > 0 else {
            return nil
        }
        
        let chosungList = ["ㄱ","ㄲ","ㄴ","ㄷ","ㄸ","ㄹ","ㅁ","ㅂ","ㅃ","ㅅ","ㅆ","ㅇ","ㅈ","ㅉ","ㅊ","ㅋ","ㅌ","ㅍ","ㅎ"]
        let code = utf16[utf16.startIndex]
        
        if code >= UInt16(koreanUnicodeRange.0) && code <= UInt16(koreanUnicodeRange.1) {
            let unicode = code - UInt16(koreanUnicodeRange.0)
            let chosungIndex = Int(unicode / 21 / 28)
            return chosungList[chosungIndex]
        }
        
        return String(first!)
    }
}
  • 아래와 같이 Datasource, Delegate을 설정해준다.
import UIKit

class SectionIndexViewController: UIViewController {
    
    @IBOutlet weak var listTableView: UITableView!
    
    let list = Region.generateData()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
    }
}




extension SectionIndexViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return list.count
    }
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list[section].countries.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        let target = list[indexPath.section].countries[indexPath.row]
        cell.textLabel?.text = target
        
        return cell
    }
    
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return list[section].title
    }
}
  • 그러면 아래와 같이 index가 옆에 생기게 된다.

  • section index의 폰트를 바꿔보자
    override func viewDidLoad() {
        super.viewDidLoad()
        
        listTableView.sectionIndexColor = UIColor.systemBlue
        listTableView.sectionIndexBackgroundColor = UIColor.secondarySystemBackground
        listTableView.sectionIndexTrackingBackgroundColor = UIColor.systemYellow
        
        
    }

0개의 댓글