iOS/Toy project

[iOS: Toy Project] Chat List

yevdev 2022. 5. 23. 00:43

๐Ÿ“Œ ๋„ค๋ฒˆ์งธ ํ”„๋กœ์ ํŠธ

์ฑ„ํŒ… ๋ฆฌ์ŠคํŠธ ์•ฑ์„ ๋งŒ๋“ค์–ด๋ณด์ž

 

 

 

1๏ธโƒฃ Data ํ™•์ธ ๋ฐ ChatListViewController ๋งŒ๋“ค๊ธฐ

ํŒจ์บ ์—์„œ ์ œ๊ณตํ•ด์ค€ ๋ฐ์ดํ„ฐ swift ํŒŒ์ผ
ํŒจ์บ ์—์„œ ์ œ๊ณตํ•ด์ค€ Assests ํŒŒ์ผ

 

 

 

2๏ธโƒฃ Auto Layout

CollectionView์™€ View ์‚ฌ์ด์˜ Auto Layout
imageView AutoLayout
์ด๋ฆ„ Label๊ณผ ์ด๋ฏธ์ง€ ์‚ฌ์ด์˜ Auto Layout
์ด๋ฆ„๊ณผ ๋Œ€ํ™”๋‚ด์šฉ์‚ฌ์ด์˜ Auto Layout
๋‚ ์งœ์™€ ContentView ์‚ฌ์ด์˜ Auto Layout
๋Œ€ํ™”๋‚ด์šฉ๊ณผ ๋‚ ์งœ ์‚ฌ์ด์˜ ์ˆ˜ํ‰๋ฐฉํ–ฅ ๊ฑฐ๋ฆฌ๋‘๊ธฐ (๊ฒน์น˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ)

 

 

 

3๏ธโƒฃ UICollectionViewCell ๋งŒ๋“ค๊ธฐ

Cell ์—ฐ๊ฒฐ , ์žฌ์‚ฌ์šฉ ID ์‹๋ณ„์ž๋„ ์„ค์ •

// ChatListCollectionViewCell.swift

import UIKit

class ChatListCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var thumbnail: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var chatLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    
    // Chat.swift ํŒŒ์ผ์— ์žˆ๋Š” ๋‚ด์šฉ์„ ๋ฐ›์•„์„œ ๋‚ด์šฉ ์—…๋ฐ์ดํŠธ
    func configure(_ chat: Chat){
        thumbnail.image = UIImage(named: chat.name)
        nameLabel.text = chat.name
        chatLabel.text = chat.chat
        dateLabel.text = chat.date
    }
}

 

 

 

4๏ธโƒฃ Data๊ฐ€ ๋“ค์–ด๊ฐ€๊ธฐ ์ „๊นŒ์ง€ ViewController์— ์ž‘์„ฑ๋˜์–ด์•ผ ํ•  ์ฝ”๋“œ (์ค€์ˆ˜ํ•  ํ”„๋กœํ† ์ฝœ..)

//
//  ChatListViewController.swift
//  Chat List
//
//  Created by ์˜ค์˜ˆ์ง„ on 2022/05/22.
//

import UIKit

class ChatListViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    
    let chatList: [Chat] = Chat.list
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Data, Presentation, Layout
        
        // dataSource : data์™€ presentation์„ ํ‘œํ˜„ํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ„์ž„ํ•ด์ฃผ๋Š” ์—ญํ• 
        collectionView.dataSource = self    // self : ๋ฐ”๋กœ viewController ๋‚˜์•ผ ๋‚˜
        // delegate : Layout๋„ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ„์ž„
        collectionView.delegate = self  // ์ด๊ฒƒ๋„ viewController
        // self = ์œ„์ž„๋‹นํ•˜๋Š” ๊ฐ์ฒด๋กœ ๋ฐ”๋กœ viewController ์ž์‹ ์ž„
        

    }

}

// dataSource์™€ delegate ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ธฐ ์œ„ํ•œ extension (๊ฐ ํ”„๋กœํ† ์ฝœ์— ํ•„์š”ํ•œ ๋ฉ”์†Œ๋“œ๋“ค์„ ์ž‘์„ฑ)
extension ChatListViewController: UICollectionViewDataSource {
    
    // CollectionView์— ํ‘œํ˜„๋˜๋Š” ์•„์ดํ…œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ช‡๊ฐœ์ธ์ง€ = chat list์˜ ๊ฐœ์ˆ˜๋งŒํผ!
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return chatList.count
    }
    
    // cell์„ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ• ์ง€
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        // ์žฌ์‚ฌ์šฉ ๊ตฌ๋ถ„์ž๋ฅผ ์ด์šฉํ•˜์—ฌ cell์„ ๊ฐ€์ ธ์˜ค๊ธฐ
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ChatListCollectionViewCell", for: indexPath)
        return cell
    }
    
}

// for Layout
// ChatListViewController๊ฐ€ FlowLayout์— ๋Œ€ํ•œ ์—ญํ• ์„ ์œ„์ž„๋ฐ›์„ ๊ฒƒ์ด๋‹ค.
extension ChatListViewController: UICollectionViewDelegateFlowLayout{
    
    // Cell์˜ ์‚ฌ์ด์ฆˆ
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.bounds.width, height: 100)
    }
    
}

์•„์ง ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ X

 

 

 

5๏ธโƒฃ Data ์—…๋ฐ์ดํŠธ : ์บ์ŠคํŒ…!

// ChatListViewController.swift

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // ์žฌ์‚ฌ์šฉ ๊ตฌ๋ถ„์ž๋ฅผ ์ด์šฉํ•˜์—ฌ cell์„ ๊ฐ€์ ธ์˜ค๊ธฐ
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ChatListCollectionViewCell", for: indexPath) as? ChatListCollectionViewCell else {
        return UICollectionViewCell()   // ์บ์ŠคํŒ…์ด ์‹คํŒจํ•œ ๊ฒฝ์šฐ ์‹คํ–‰
    }

    // ์บ์ŠคํŒ…์— ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ ์‹คํ–‰๋˜๋Š” ์•„๋ž˜์˜ ์ฝ”๋“œ
    let chat = chatList[indexPath.item]
    cell.configure(chat)
    return cell
}

๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ

 

 

 

6๏ธโƒฃ ๋ณด์™„

 

1. ์ฑ„ํŒ…๋‚ด์šฉ ๋‘์ค„๋กœ ํ‘œํ˜„

CollectionView์˜ Estimate Size๋ฅผ None์œผ๋กœ ์„ค์ •

โ—๏ธ๊ฐ•์˜์—์„œ๋Š” ์ด๋ ‡๊ฒŒํ•˜๋ฉด ๋œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ ๋‚˜๋Š” ์•ˆ๋˜๊ธธ๋ž˜.. ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ด„

๋ฐ”๋กœ numberOfLines๋ฅผ ํ†ตํ•ด Label์˜ ์ค„๋ฐ”๊ฟˆ ์†์„ฑ ๊ฐ’์„ ์ฃผ์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

//  ChatListCollectionViewCell.swift

import UIKit

class ChatListCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var thumbnail: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var chatLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    
    // Chat.swift ํŒŒ์ผ์— ์žˆ๋Š” ๋‚ด์šฉ์„ ๋ฐ›์•„์„œ ๋‚ด์šฉ ์—…๋ฐ์ดํŠธ
    func configure(_ chat: Chat){
        thumbnail.image = UIImage(named: chat.name)
        nameLabel.text = chat.name
        chatLabel.text = chat.chat
        dateLabel.text = chat.date
        
        // ๋ฐ”๋กœ ์ด๋ ‡๊ฒก~!
        chatLabel.numberOfLines = 2
    }
}

 

 

2. ์ฑ„ํŒ… ๋‚ด์šฉ์ด๋ž‘ ๋‚ ์งœ ์‚ฌ์ด์˜ ํž˜์˜ ๊ท ํ˜• ๋น„๋“ฑํ•˜์—ฌ ๋‚ ์งœ๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ

Content Hugging Priority์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์œผ๋ฉด ๋‚ด ํฌ๊ธฐ ์œ ์ง€. ์šฐ์„ ์ˆœ์œ„ ๋‚ฎ์œผ๋ฉด ํฌ๊ธฐ ๋Š˜์–ด๋‚จ

Content Compression Resistence Priority : ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์œผ๋ฉด ๋‚ด ํฌ๊ธฐ ์œ ์ง€. ์šฐ์„ ์ˆœ์œ„ ๋‚ฎ์œผ๋ฉด ํฌ๊ธฐ ์ž‘์•„์ง

chatLabel๋ณด๋‹ค dateLabel์ด ๋” ํž˜์ด ์Ž„๋„๋ก ํ•ด๋ณด์Ÿˆ

chatLabel์ด dateLabel๋ณด๋‹ค ์•ฝํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—,

chatLabel์˜ Content Compression Resistence Priority๋ฅผ Row(250)์œผ๋กœ ๋งž์ถ”๊ธฐ

-> ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํž˜์˜ ๊ท ํ˜•์— ์žˆ์–ด์„œ chatLabel์€ dateLabel๋ณด๋‹ค ์•ฝํ•˜์—ฌ ์ชผ๊ทธ๋ผ๋“ ๋‹ค.

 

๋ณด์™„ํ•œ ํ™”๋ฉด (์ฑ„ํŒ… ๋‚ด์šฉ, ๋‚ ์งœ ๋‚ด์šฉ)

 

3. ๋‚ ์งœ ํ‘œํ˜„ ์ค„์ด๊ธฐ

- DateFormatter() ๊ฐ์ฒด ์ด์šฉ

//
//  ChatListCollectionViewCell.swift
//  Chat List
//
//  Created by ์˜ค์˜ˆ์ง„ on 2022/05/22.
//

import UIKit

class ChatListCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var thumbnail: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var chatLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    
    // Chat.swift ํŒŒ์ผ์— ์žˆ๋Š” ๋‚ด์šฉ์„ ๋ฐ›์•„์„œ ๋‚ด์šฉ ์—…๋ฐ์ดํŠธ
    func configure(_ chat: Chat){
        thumbnail.image = UIImage(named: chat.name)
        nameLabel.text = chat.name
        chatLabel.text = chat.chat
        dateLabel.text = formattedDateString(dateString: chat.date)
        chatLabel.numberOfLines = 2
    }
    
    func formattedDateString(dateString: String) -> String {
        
        // String -> Date -> String ์ˆœ์œผ๋กœ ๋ณ€ํ™˜์‹œ์ผœ์ค˜์•ผํ•จ.
        // 2022-04-01 > 4/1
        
        // DateFormatter() ๊ฐ์ฒด ์ด์šฉ
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        
        // String -> Date ๋ณ€ํ™˜
        if let date = formatter.date(from: dateString){
            formatter.dateFormat = "M/d"
            
            // Date -> String ๋ณ€ํ™˜
            return formatter.string(from: date)
        } else {
            return ""
        }
    }
}

๋ณด์™„๋œ ํ™”๋ฉด (๋‚ ์งœ ์ถ•์•ฝ)

 

 

4. ๋‚ ์งœ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ๋ฐ”๊พธ๊ธฐ (์ตœ์‹  ๋Œ€ํ™”๊ฐ€ ๊ฐ€์žฅ ์œ„๋กœ!)

- ๋ฐฐ์—ด ๋‚ด์žฅํ•จ์ˆ˜์ธ sort๋ฅผ ์ด์šฉ

// ChatListViewController.swift

// ...

override func viewDidLoad() {
        //...
        
        // closure ํ‘œํ˜„๋ฐฉ๋ฒ•์„ ํ†ตํ•ด์„œ sort ํ•จ์ˆ˜ ์ด์šฉ
        chatList = chatList.sorted(by: {chat1, chat2 in return chat1.date > chat2.date})
        // -> date์— ๋”ฐ๋ผ ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ chatList๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

}

๋ณด์™„๋œ ํ™”๋ฉด (๋‚ ์งœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ)

 

 

5. ์ธ๋„ค์ผ ํ…Œ๋‘๋ฆฌ ์•ฝ๊ฐ„ ๋‘ฅ๊ธ€๊ฒŒ ๋งŒ๋“ค๊ธฐ

- Storyboard์—์„œ ๊บผ๋‚ด์™€์„œ ์ฝ”๋“œ๋กœ ๋ฐ”๊ฟ”๋ณด์ž!

awakeFromNib() ํ•จ์ˆ˜ ์‚ฌ์šฉ -> storyboard์—์„œ ๊บผ๋‚ด์˜ฌ ๋•Œ, ๋ถˆ๋ฆฌ์–ด์ง€๋Š” ํ•จ์ˆ˜

// ChatListCollectionViewCell.swift

import UIKit

class ChatListCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var thumbnail: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var chatLabel: UILabel!
    @IBOutlet weak var dateLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        thumbnail.layer.cornerRadius = 10 
    }
    
    // ....
}

๋ณด์™„๋œ ํ™”๋ฉด (๋‘ฅ๊ธ€์–ด์ง„ ์ธ๋„ค์ผ)

 

 

๐Ÿš€ ๊ตฌํ˜„ ์™„๋ฃŒ!

 

 

 


๐Ÿ“Œ ์ •๋ฆฌ,

  • dataSource : data์™€ presentation์„ ํ‘œํ˜„ํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ„์ž„ํ•ด์ฃผ๋Š” ํ”„๋กœํ† ์ฝœ
  • delegate : layout์„ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ„์ž„ํ•ด์ฃผ๋Š” ํ”„๋กœํ† ์ฝœ
  • ์œ„์˜ ๋‘๊ฐœ์˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•  extenstion ์ฝ”๋“œ๋„ ์ž‘์„ฑํ•ด๋ดค์Œ
  • Content Hugging Priority์™€ Content Compression Resistence Priority์„ ํ†ตํ•œ component๊ฐ„์˜ ํž˜์˜ ์„ธ๊ธฐ ๋ณ€๊ฒฝ
  • DateFormatter() ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•œ ๋‚ ์งœ ํ˜•์‹ ๋ณ€๊ฒฝ
  • ํด๋กœ์ € ํ‘œํ˜„์„ ํ†ตํ•œ sort() ํ•จ์ˆ˜ ์‚ฌ์šฉ -> ๋ฐฐ์—ด์˜ ํŠน์ • ์š”์†Œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•œ ์ •๋ ฌ

 

 

 


Reference

ํŒจ์ŠคํŠธ์บ ํผ์Šค ์˜จ๋ผ์ธ ๊ฐ•์˜

'iOS > Toy project' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[iOS : Toy Project] Apple Framework List (2)  (0) 2022.05.28
[iOS : Toy Project] Apple Framework List (1)  (0) 2022.05.28
[iOS : Toy Project] Stock Rank  (0) 2022.05.21
[iOS : Toy Project] Simple Weather  (0) 2022.05.17
[iOS : Toy Project] Symbol Roller  (0) 2022.05.12