개발일기/IOS

[Swift] - CollectionView 정리

코딩하는빵친자 2024. 3. 15. 13:32
  • collectionView의 레이아웃
    • FlowLayout
      • Gird형태의 레이아웃을 쉽게 구성할 수 있도록 도와주는 클래스, UICollectionViewDelegateFlowLayout 대리자를 통해서도 지정가능
      let layout = UICollectionViewFlowLayout() 
      layout.scrollDirection = .vertical  // 스크롤의 방향(기본값 vertical)
      layout.minimumLineSpacing = 20  // 그리드 줄 간격(기본값 10)
      layout.minimumInteritemSpacing = 20   // 그리드 행 간격(기본값 10)
      layout.itemSize = CGSize(width:100, height:100)  // 각 cell의 크기 설정, 기본 크기는 (50, 50)
      layout.estimatedItemSize = CGSize(width:100, height:100) // 동적으로 cell의 크기를 계산할 때 성능을 높여준다고 한다.
      layout.sectionInset = UIEdgeInsets(top:30, left:30, bottom:30. right:30)   // section에 대한 여백을 설정한다(contentView 여백)
      
      // header, footer크기 지정
      // 스크롤 방향에 따라서 크기가 영향을 받는다(vertical은 height값만 갖고 계산, horizontal일 경우 width만 영향을 받는다)
      layout.headerReferenceSize = CGSize(width: 50, height: 100)
      layout.footerReferenceSize = CGSize(width: 50, height: 100)
      
      // header, footer를 고정시킴(기본값 false)
      layout.sectionHeadersPintoVisibleBounds = true
      layout.sectionFootersPintoVisibleBounds = true
      
    • compositionalLayout
      • item,group, section, layout으로 구성된다. 하나의 layout에 section, section안에 group, group안에 item들이 있다.

  • collectionViewCell
    • collectionViewCell은 단일데이터 항목으로, 있는 그대로 사용하거나 하위 클래스로 추가하여 추가 속성 및 메서드를 추가할 수 있다. 재사용이 가능하기 때문에 커스텀하여 주로 사용한다.
  • scrollView
    • scrollView를 내장하고 있어 cell의 개수가 collectionview의 frame보다 넘어가게 되더라도 알아서 스크롤이 가능하게끔 만든다.
    • 보톨 가로 스크롤의 경우 scrollView와 StackView를 함께 사용하는 편이다.
  • Header & Footer
    • UICollectionView는 Header와 Footer도 가질 수 있다.
  • collectionView Protocol
    • CollectionViewDelegate
      • 선택, highlight, action 등을 지정할 때 주로 사용
      • 선택 관련 메서드로는 shouldSelectItemAt, didSelectItemAt, shouldDeselectItemAt, didDeselectItemAt
      • highlight관련 메서드로는 shouldHighlightItemAt, didHighlightItemAt, didUnhighlightItemAt
    • CollectionViewDataSource
      • 데이터를 관리하는 함수들을 포함하고 있다. 뿐만 아니라 headerView와 FooterView를 설정해주는 함수들도 포함하고 있다.
      • numberOfItemsInSection : cell을 몇 개 만들 것인지 설정, 즉 collectionView의 section안에 몇 개의 item을 둘 지 설정하는 것, 그래서 만약 section이 여러개고 다 다른 개수를 갖고 있으면 section변수를 사용해서 분기 처리 해주면 된다.
      • cellForItemAt : 재사용하는 cell에 대한 데이터 오브젝트를 요청하는 함수이다. 여기서 각 cell 마다 다른 데이터를 넘겨줄 수 있다.
    CollectionView에서 이미지 로딩 겹치는 문제!!!(이것 때문에 삽질 엄청함)
    import Foundation
    import UIKit
    
    class CustomImageView: UIImageView {
    
        var task: URLSessionDataTask!
        var imageCache = NSCache<AnyObject, AnyObject>()
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.image = UIImage(named: "default_thum_vod_movie_list")
        }
        
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            self.image = UIImage(named: "default_thum_vod_movie_list")
        }
        
        func loadImage(imageUrl: String) {
            image = nil
            let urlstr = (imageUrl == "") ? ImageURL.BACK_IMAGE_BLUREFFECT : imageUrl
            let ssl = URL(string: urlstr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!.applySSL())!
            let placeholderImageView = UIImageView(image: UIImage(named: "default_thum_vod_movie_list"))
            placeholderImageView.contentMode = .scaleAspectFit
            placeholderImageView.backgroundColor = .black
            if let task = task{
                task.cancel()
            }
    
    //        if let imageFromCache = imageCache.object(forKey: ssl.absoluteString as AnyObject) as? UIImage{
    //            self.image = imageFromCache
    //            return
    //        }
            
            task = URLSession.shared.dataTask(with: ssl) { data, response, error in
                if let error = error as NSError?, error.code == NSURLErrorCancelled{
                    return
                }
                guard let data = data, let newImage = UIImage(data: data) else {
                    print("\\(ssl) load fail...")
                    return
                }
    //            self.imageCache.setObject(newImage, forKey: ssl.absoluteString as AnyObject)
                
                DispatchQueue.main.async{
                    self.image = newImage
                }
            }
            
            task.resume()
        }
    }
    
  • → 비동기로 URLSession을 실행하여 이미지를 띄우면 된다.
728x90