# UIKit 2 : 리스트뷰 && 그리드뷰

이은호·2023년 2월 19일
0

swift

목록 보기
3/8
post-thumbnail

리스트와 그리드는 필수다. 결국 메인이 될 페이지를 개발할때 사용하는 컴포넌트다.
크게 UITableView, UICollectionView 둘이 비슷하기도 하고 테이블이 콜렉션에 종속되어있는 느낌이라 콜렉션 뷰를 학습할 것이다.

콜렉션뷰로 리스트와 그리드를 개발할때는 3개만 고려하자. [데이터,프레젠테이션(셀 표현),레이아웃]

리스트뷰 (stock)

뿌리기

1.먼저 뷰안에 컬렉션뷰를 만들고 안의 내용을 꾸며준다.(생략)
2.그리고 컬렉션셀 파일을 만든다.
StockRankCollectionViewCell

//
//  StockRankCollectionViewCell.swift
//  stockmarket
//
//  Created by 이은호 on 2023/02/18.
//

import UIKit

class StockRankCollectionViewCell: UICollectionViewCell {
    
}

3.뷰컨->컬렉션뷰->컬렉션뷰셀의 클래스와 파일을 연결하고, identifier도 동일한 이름으로 작성한다.
4.어시스턴트 코드

//
//  StockMarketViewController.swift
//  stockmarket
//
//  Created by 이은호 on 2023/02/18.
//

import UIKit

class StockMarketViewController: UIViewController {

    let stockList: [StockModel] = StockModel.list
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.dataSource = self
        collectionView.delegate = self
    }
}

extension StockMarketViewController: UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return stockList.count
    }//리스트의 크기
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StockRankCollectionViewCell", for: indexPath)
        return cell
    }//indentifier
    
}
extension StockMarketViewController: UICollectionViewDelegate{
    
}


배치는 되었지만 모양이 이상하다. 고쳐보도록 하자.

꾸미기(⚠️)

바로 여기서 비어있는 UICollectionViewDelegate를 핸들링하게 된다.
이슈가 하나 있는데 생성되는것은 UICollectionViewDelegated이지만 FlowLayout를 사용해야한다!

extension StockMarketViewController: UICollectionViewDelegateFlowLayout{
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.bounds.width, height: 80)
    }
}

넣기(데이터)

이 작업은 뷰컨파일이 아닌 뷰컨셀파일에서 작업한다.

import UIKit

class StockRankCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var rankLabel: UILabel!
    @IBOutlet weak var companyName: UILabel!
    @IBOutlet weak var priceLabel: UILabel!
    @IBOutlet weak var companyLogoImage: UIImageView!
    @IBOutlet weak var diffLabel: UILabel!
    
    
    
    func configure(_ stock:StockModel){
        rankLabel.text = "\(stock.rank)"
        companyName.text = "\(stock.name)"
        priceLabel.text = "\(stock.price)"
        diffLabel.text = "\(stock.diff) 원"
        companyLogoImage.image = UIImage(named: stock.imageName)
        
    }
}

이경우에는 아무것도 안바뀌는데 상위 클래스와 통신이 안되었기때문이다.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StockRankCollectionViewCell", for: indexPath) as? StockRankCollectionViewCell else{
            return UICollectionViewCell()
        }
        print(indexPath.item)
        let stock = stockList[indexPath.item]
        cell.configure(stock)
        return cell
    }//indentifier

guard에 대해서는 부록에서 복습해보도록 하자

디테일

diff가 음수이면 파란색으로 디자인해주자.

func configure(_ stock:StockModel){
        rankLabel.text = "\(stock.rank)"
        companyName.text = "\(stock.name)"
        priceLabel.text = "\(convertCurrency(price:stock.price))원"
        diffLabel.text = "\(stock.diff)%"
        companyLogoImage.image = UIImage(named: stock.imageName)
        if stock.diff < 0 {
            diffLabel.textColor = UIColor.blue
        }
    }
    
diffLabel.textColor = stock.diff < 0 ? UIColor.systemBlue : UIColor.systemRed

밑에처럼 표현도 가능하다.

리스트뷰 (chat)

디자인(생략) 완벽한 반복이다.
다른 부분이 있다면

디테일

  1. 메세지가 너무 길어서 생략을 해줘야한다.
    부동산(?)사이즈가 오토매틱으로 되어있기때문이다.

  1. 그리고 서로다른 두 요소가 연속으로있을때, 어떤게 중요한지 우선순위를 둘수도 있다.
    대화내용이 상대적으로 덜 중요하기 때문에 우측하단의 우선순위를 낮춰준다.

3.날짜형식도 월-일만 나오게 하자.

func FormmaterDate(dateString:String)->String{
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    if let date = formatter.date(from: dateString) {
        formatter.dateFormat = "M/d"
        return formatter.string(from: date)
    }else{
        return ""
    }    
}

과제

날짜를 내림차순으로 정렬해보자

chatList = chatList.sorted(by: { chat1, chat2 in
            return chat1.date > chat2.date
        })

이미지의 테두리를 깎아보자

override func awakeFromNib() {
        super.awakeFromNib()
        userImage.layer.cornerRadius = 20
    }

그리드뷰

정말 간단하다. 레이아웃만 만져주면 된다.

extension AppViewController: UICollectionViewDelegateFlowLayout{
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        let width = (collectionView.bounds.width - 20) / 3
        let height = width * 1.5
        return CGSize(width: width, height: height)
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 10
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 10
    }
}

네비게이션

스토리보드의 상단바를 클릭하고 editor -> embed in -> navigation controller 클릭
타이틀을 스토리보드에서 클릭해서 수정해주면 된다.
콜렉션뷰를 세이프에이리어 밖까지 지정해주고 constant까지 0으로 설정해주자. 네비게이션에 블러처리가 된다.

그리드 인셋

인셋이 뭐냐하면 마진이다 ㅋㅋㅋ

override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.contentInset = UIEdgeInsets(top: 20, left: 10, bottom: 0, right: 10)
    }

클릭

이제 요소들을 클릭했을때 정보를 출력할 수 있도록 해보자.

extension AppViewController: UICollectionViewDelegate{
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let app = list[indexPath.item]
        print("\(app.name)")
        print("\(app.description)")
    }
}

디테일

4행으로 만들면 글자가 잘린다.

부록

guard 참고자료

guard문은 조건이 틀린 경우는 모두 버리고, 우리가 원하는 조건만 통과시키겠다는 기능으로 사용된다. if문과의 차이점으로 보면 if문은 '~면 ~해라' 의 실행 구문이지만, guard는 '~아니면 끝내라' 라는 의미이기 때문이다. 따라서 guard문은 '빠른 종료'의 핵심이라고 한다.

guard구문은 함수나 메서드 혹은 반복문 안에서만 사용할 수 있다는 한계점이 있다. 쉽게 말해 {}안에서만 사용한다는 것이다.

사실 if문보다 특별히 잘난점도 못난점도 없지만 if else가 {}을 두번쓰는 반면, {}을 한 번 쓰기 때문에 가독성이 조금 좋아진다고 보면 되겠다.

...조금 잘난점이 있다.

func의 _(언더바)의미

파라미터에 _을 선언하게 되면, 해당 파라미터의 레이블을 생략할 수 있게 된다.

func solution(str:String) {
    print(str)
}
solution(str:"사랑해")
func solution(_ str:String) {
    print(str)
}
solution("사랑해")

0개의 댓글