728x90
반응형

[Review] (5주차) 실습

2022.07.16 - [Dev/Swift] - [Xcode] iOS Swift 앱 개발 Byte Degree - week.05

 

[Xcode] iOS Swift 앱 개발 Byte Degree - week.05

[Review] (4주차) 실습 2022.07.10 - [Dev/Swift] - [Xcode] iOS Swift 앱 개발 Byte Degree - week.04 [Xcode] iOS Swift 앱 개발 Byte Degree - week.04 [Review] (3주차) 실습 2022.07.01 - [Swift] - [Xcode]..

sarahee.tistory.com


최종 구현

 

그리드 레이아웃 변경 작업

FocusViewController 및 QuickFocusListViewController의  레이아웃 작업 변경(UICollectionViewCompositionalLayout 응용)

 

FocusViewController code 기존 수정 해설
item의 .fractionalWidth(1) 1 0.9 크기 조절
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item]) vertical horizontal 스크롤 방향: 세로 → 가로
section.orthogonalScrollingBehavior = .groupPagingCentered   신규 추가 스크롤 시 item 중앙 정렬
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20) leading: 20, trailing: 20 leading: 5, trailing: 5 좌우 padding 줄이기
group의 .fractionalWidth(1) 1 0.9 item과 동일하게 설정(group padding이 별도로 설정되지 않도록)
section.interGroupSpacing = 10 10 -25 좌우 여백값 조절

 

QuickFocusListViewController code 기존 수정 해설
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2) subitem: item, count: 2 subitems: [item] 동적으로 할당하도록 개수  설정 해제
section.orthogonalScrollingBehavior = .continuous   신규 추가 스크롤 시 item 정렬되지 않도록(이동한 만큼 위치)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
subitems: [item] subitem: item, count: 1 변경사항 복구
section.interGroupSpacing = 20 20 10 좌우 padding 줄이기

QuickFocusListViewController의 UIViewController에서

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
        // 기존
//        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2)
        // 변경: 유연하게 할당될 수 있도록
		let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        group.interItemSpacing = .fixed(10)
        
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 30, leading: 20, bottom: 30, trailing: 20)
        section.interGroupSpacing = 20
        // 추가: .continuous, .groupPagingCentered
        section.orthogonalScrollingBehavior = .continuous

Collection View Cell

수평적으로 화면 조회되지만, 각 화면에 하나의 group만 존재하도록 설정됨

(참고) corner의 값 조절 - 코드에 반영하지 않음

collectionView.collectionViewLayout = layout()
collectionView.delegate = self
// 추가: width의 값이 동적으로 조절
collectionView.clipsToBounds = true

→ group의 fractionalWidth도 item과 동일하게 설정해 주어야 함 + spacing 값 또한 조절


UICollectionViewCompositionalLayout

출처:  https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout

func createBasicListLayout() -> UICollectionViewLayout { 
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                  
                                         heightDimension: .fractionalHeight(1.0))    
    let item = NSCollectionLayoutItem(layoutSize: itemSize)  
  
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                          
                                          heightDimension: .absolute(44))    
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,                                                   
                                                     subitems: [item])  
  
    let section = NSCollectionLayoutSection(group: group)    

    let layout = UICollectionViewCompositionalLayout(section: section)    
    return layout
}

group.interItemSpacing에 int 값을 넣으면 다음과 같은 오류 발생

Cannot assign value of type 'int' to type 'NSCollectionLayoutSpacing?'

 

group size의 fractionWidth를 item size와 동일하게 0.5로 설정할 경우 다음과 같은 화면 조회

두 item처럼 보이는 부분이 하나의 item으로 설정됨

QuickFocusCell의 count를 subitems: [item] → subitem: item, count: 1 설정

좌측부터 차례대로 FocusViewController, QuickFocusListViewController

최종 코드

//
//  FocusViewController.swift
//  HeadSpaceFocus
//
//  Created by sehee on 2022/07/10.
//

import UIKit

class FocusViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var refreshButton: UIButton!
    
    var curated: Bool = false
    var items: [Focus] = Focus.list
    
    typealias Item = Focus
    enum Section {
        case main
    }
    var datasource: UICollectionViewDiffableDataSource<Section, Item>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        refreshButton.layer.cornerRadius = 10
        
        // Presentation: Diffable Datasource + Cell Provider
        datasource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FocusCell", for: indexPath) as? FocusCell else {
                return nil
            }
            cell.configure(item)
            return cell
        })
        
        // Data: Snapshot
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        snapshot.appendItems(items, toSection: .main)
        datasource.apply(snapshot)
        
        // Layout
        collectionView.collectionViewLayout = layout()
        collectionView.delegate = self
        
        updateButtonTitle()
    }
    
    private func layout() -> UICollectionViewCompositionalLayout {
        
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.9), heightDimension: .estimated(50))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.9), heightDimension: .estimated(50))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 5, bottom: 10, trailing: 5)
        section.interGroupSpacing = -25
        section.orthogonalScrollingBehavior = .groupPagingCentered
        
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }
    
    func updateButtonTitle() {
        let title = curated ? "See All" : "See Recommendation"
        refreshButton.setTitle(title, for: .normal)
    }
    
    @IBAction func refreshButtonTapped(_ sender: Any) {
        curated.toggle()
        
        self.items = curated ? Focus.recommendations : Focus.list
        
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        snapshot.appendItems(items, toSection: .main)
        datasource.apply(snapshot)
        
        updateButtonTitle()
    }
}

extension FocusViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let item = items[indexPath.item]
//        print(">>> \(item.title)")
        
        let storyboard = UIStoryboard(name: "QuickFocus", bundle: nil)
        let vc = storyboard.instantiateViewController(withIdentifier: "QuickFocusListViewController") as! QuickFocusListViewController
        vc.title = item.title
//        present(vc, animated: true)
        navigationController?.pushViewController(vc, animated: true)
    }
}
//
//  QuickFocusListViewController.swift
//  HeadSpaceFocus
//
//  Created by sehee on 2022/07/21.
//

import UIKit

class QuickFocusListViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    let breathingList = QuickFocus.breathing
    let walkingList = QuickFocus.walking
    
    enum Section: CaseIterable {
        case breathe
        case walking
        
        var title: String {
            switch self {
            case .breathe: return "Breathing exercises"
            case .walking: return "Mindful walks"
            }
        }
    }
    
    typealias Item = QuickFocus
    var datasource: UICollectionViewDiffableDataSource<Section, Item>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // enum Section CaseIterable 생성한 코드가 다음 내용과 동일
//        Section.allCases
//        let allItems: [Section] = [.breathe, .walking]
        // 생성 코드가 다음과 같이 쓰일 수 있음
//        let section: Section = .breathe
//        section.title
        
        // Presentation
        datasource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "QuickFocusCell", for: indexPath) as? QuickFocusCell else {
                return nil
            }
            cell.configure(item)
            return cell
        })
        
        datasource.supplementaryViewProvider = { (collectionView, kind, indexPath) in
            guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "QuickFocusHeaderView", for: indexPath) as? QuickFocusHeaderView else {
                return nil
            }
            let allSections = Section.allCases
            let section = allSections[indexPath.section]
            header.configure(section.title)
            return header
        }
        
        // Data
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.breathe, .walking])
        // 위의 코드와 동일
//        snapshot.appendSections(Section.allCases)
        snapshot.appendItems(breathingList, toSection: .breathe)
        snapshot.appendItems(walkingList, toSection: .walking)
        datasource.apply(snapshot)
        
        // Layout
        collectionView.collectionViewLayout = layout()
        self.navigationItem.largeTitleDisplayMode = .never
    }
    private func layout() -> UICollectionViewCompositionalLayout {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .estimated(50))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .estimated(50))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)
        group.interItemSpacing = .fixed(10)
        
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 30, leading: 20, bottom: 30, trailing: 20)
        section.interGroupSpacing = 10
        section.orthogonalScrollingBehavior = .continuous
        
        let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50))
        let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
        section.boundarySupplementaryItems = [header]
        
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }
}

 

 

728x90
728x90

+ Recent posts