관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 2. 스크롤 영역을 암시해주는 Carousel 구현 - 포커스 영역 이펙트 본문

UI 컴포넌트 (swift)

[iOS - swift] 2. 스크롤 영역을 암시해주는 Carousel 구현 - 포커스 영역 이펙트

jake-kim 2022. 6. 27. 23:45

1. 스크롤 영역을 암시해주는 Carousel 구현 - (UICollectionView, 수평 스크롤 뷰, paging 구현)

2. 스크롤 영역을 암시해주는 Carousel 구현 - 포커스 영역 이펙트

 

첫번째 글에서 구현한 Carousel)

좌, 우측에 item이 보이도록 스크롤 되는 Carousel

이번 글에서 알아볼, 셀에 효과가 들어간 Carousel)

* 포커스 되는 영역이 아닐 경우, dimmed 처리

* 구현 전에 이전까지 구현된 코드 다운로드: https://github.com/JK0369/ExCarousel

모델 생성

  • iOS에서 셀은 항상 reuse 되므로, cell에 직접 접근하여 속성을 변경하는 것보다 dataSource에 속성을 지정해준 다음 reloadData하도록 설계할것
    • 상태 관리를 dataSource에서만 하도록 구현
  • 기존에 아래처럼 있던 코드를 MyModel을 사용하여 수정
// 이전 코드
private var items = (0...100).map { _ in randomColor }
// 변경 코드
import Foundation
import UIKit

struct MyModel {
  let color: UIColor
  var isDimmed: Bool
}

private var items = (0...100).map { _ in
  MyModel(color: randomColor, isDimmed: true)
}
  • 커스텀 셀에도 isDimmed 적용
// MyCollectionViewCell

private let dimmedView: UIView = {
  let view = UIView()
  view.backgroundColor = .black.withAlphaComponent(0.45)
  view.translatesAutoresizingMaskIntoConstraints = false
  return view
}()

override func prepareForReuse() {
  super.prepareForReuse()
  
  self.prepare(color: nil, isDimmed: true)
}

func prepare(color: UIColor?, isDimmed: Bool) {
  self.myView.backgroundColor = color
  self.dimmedView.isHidden = !isDimmed
}

포커스 영역 이펙트 적용

  • UICollectionView는 UIScrollView의 서브클래싱이기 때문에 UIScrollView의 델리게이트 메소드인 scrollViewDidScroll를 구현
    • 스크롤이 완료되었을때 index값을 알아내어, 해당 index의 isDimmed를 false로 만드는 것
    • 이전 index도 저장해놓고, 이전 index의 isDimmed를 다시 true로 설정
// ViewController

// 이전 인덱스를 저장해놓기 위해 선언
private var previousIndex: Int?

...

extension ViewController: UICollectionViewDelegateFlowLayout {
  func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let scrolledOffset = scrollView.contentOffset.x + scrollView.contentInset.left
    let cellWidth = Const.itemSize.width + Const.itemSpacing
    let index = Int(round(scrolledOffset / cellWidth))
    self.items[index].isDimmed = false
    
    defer {
      self.previousIndex = index
      self.collectionView.reloadData()
    }
    
    guard
      let previousIndex = self.previousIndex,
      previousIndex != index
    else { return }
    self.items[previousIndex].isDimmed = true
  }
}

* 전체 코드: https://github.com/JK0369/ExCarouselWithAnimation

Comments