안녕하세요 !
회사에서 컬렉션뷰 혹은 테이블뷰에 스켈레톤뷰를 적용해야해서 어떻게 할까 인터넷을 검색해보았습니다.
https://github.com/Juanpe/SkeletonView
많은 분들이 이 라이브러리 를 사용하시더라구요
근데 저희 앱에 구현되어있는 테이블뷰는 이런식이었습니다.
ViewModel.data
.bind(to: collectionView.rx.items) { collectionView, row, element in
let cell = UICollectionViewCell()
return cell
}
.disposed(by: disposeBag)
대강 요런 식으로 그냥 모델에 바인딩해주는 방식이었어요.
근데 저기 SkeletonView 리드미에 보면 일반 UIKit 을 사용 할 때 쓰는 Delegate 방식에서의 방법만 제공해주고 있어서 많이 알아봤습니다.
음... 많이 찾아보니 방법이 없어보이더라구요.. 그렇다고 스켈레톤뷰를 직업 구현하기도 까다롭고...
찾다보니 https://github.com/AnyOptional/RxSkeleton
오래된 라이브러리이지만 어떤분이 이전에 만들어두신게 있더라구요.
그럼 스켈레톤뷰를 적용하기위해서 먼저 RxDataSources 로 변경해야합니다.
(어쩔 수 없잖아... 다시 리팩토링해..!!)
이 글에서 RxDataSources 를 이용한 컬렉션뷰나 테이블뷰 만드는 방법은 다루지 않겠습니다.
자 이제 리팩토링을 다 했다고 가정하고
위 라이브러리에
https://github.com/anyoptional/RxSkeleton/tree/master/Sources
Sources 폴더에 있는 모든 코드를 가져옵니다. Rx 를 확장해서 사용하는 델리게이트 프록시 느낌이에요
오래 된 코드라 조금 손봐줘야하는데 빌드해보시고 E 라고 되어있는 부분에서 오류 날텐데 Element 로 수정하시고!
RxDataSources 구현 하실 때
RxTableViewSectionedReloadDataSource<Section>
이렇게 configureCell 해주셨던 부분 기억하시나요?
여기를
RxCollectionViewSkeletonedReloadDataSource<Section>
이렇게 확장된 스켈레톤 RxDataSource 를 이용하시면 됩니다!!
어라..? 근데 어떤 식으로 확장한건지 궁금하지 않나요??
간단하게 둘러보겠습니다.
저희가 사용한 RxCollectionViewSkeletondReloadDataSources 라는 폴더를 볼게요
//
// RxCollectionViewSkeletonedReloadDataSource.swift
// RxSkeleton
//
// Created by Archer on 2018/11/30.
//
import SkeletonView
import RxDataSources
public class RxCollectionViewSkeletonedReloadDataSource<S: SectionModelType>: RxCollectionViewSectionedReloadDataSource<S>,
SkeletonCollectionViewDataSource {
public typealias NumberOfSections = (RxCollectionViewSkeletonedReloadDataSource<S>, UICollectionView) -> Int
public typealias NumberOfItemsInSection = (RxCollectionViewSkeletonedReloadDataSource<S>, UICollectionView, Int) -> Int
public typealias ReuseIdentifierForItemAtIndexPath = (RxCollectionViewSkeletonedReloadDataSource<S>, UICollectionView, IndexPath) -> String
var numberOfSections: NumberOfSections
var numberOfItemsInSection: NumberOfItemsInSection
var reuseIdentifierForItemAtIndexPath: ReuseIdentifierForItemAtIndexPath
public init(configureCell: @escaping ConfigureCell,
configureSupplementaryView: ConfigureSupplementaryView? = nil,
moveItem: @escaping MoveItem = { _, _, _ in () },
canMoveItemAtIndexPath: @escaping CanMoveItemAtIndexPath = { _, _ in false },
numberOfSections: @escaping NumberOfSections = { _, _ in 1 },
numberOfItemsInSection: @escaping NumberOfItemsInSection = { _, cv, _ in
guard let flowlayout = cv.collectionViewLayout as? UICollectionViewFlowLayout else { return 0 }
return Int(ceil(cv.frame.height/flowlayout.itemSize.height))
},
reuseIdentifierForItemAtIndexPath: @escaping ReuseIdentifierForItemAtIndexPath) {
self.numberOfSections = numberOfSections
self.numberOfItemsInSection = numberOfItemsInSection
self.reuseIdentifierForItemAtIndexPath = reuseIdentifierForItemAtIndexPath
super.init(configureCell: configureCell,
configureSupplementaryView: configureSupplementaryView,
moveItem: moveItem, canMoveItemAtIndexPath: canMoveItemAtIndexPath)
}
public func numSections(in collectionSkeletonView: UICollectionView) -> Int {
return numberOfSections(self, collectionSkeletonView)
}
public func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numberOfItemsInSection(self, skeletonView, section)
}
public func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> String {
return reuseIdentifierForItemAtIndexPath(self, skeletonView, indexPath)
}
}
원래 사용하던 RxCollectionViewSectionedReloadDataSource 를 채택하고 있고 구현 시 필요한 데이터를 추가적으로 반환해주있어요
또한 UICollectionView+Rx 파일을 보면
Items 를 RxCollectionViewSkeletonedDataSourceProxy 를 통해서 사용하는 것을 볼 수 있어요.
델리게이트 프록시에서는 RxDataSources 로 구현한 내용을 토대로 다시 UIKit에서 구현하듯이 다시 적용하는 모습을 볼 수 있는 것 같아요.
Delegate Proxy 에 대한 이해가 많이 부족해서 다음에는 Delegate Proxy가 어떻게 동작하는지 원리를 파악해봐야겠습니다!
아무튼 기존 방법대로는 사용 할 수 없지만 RxDataSources 롤 사용 할 수 있어 무리없이 해결했네요 :]
다들 문제 없이 해결하시길!
아 그리구!!!
modelSelected 로 구현하신분들은 ItemSelected 로 변경해주셔야해요
modelSelected 로 하면 빌드는 되는데 런타임에 크래시 날거에요 참고하시길!
저는 크래시 로그에서 제대로 안알려줘서 많이 삽질했거든요!
'개발 > 개발' 카테고리의 다른 글
[iOS] - Unit Test 기본 개념 공부하기 (0) | 2022.11.18 |
---|---|
[Swift] - Array의 Count 함수는 과연 속도 차이가 있을까? (3) | 2022.11.01 |
[SwiftUI] - SwiftUI Button Hide 버튼 숨기기 (0) | 2022.10.11 |
[iOS] - Carthage 따라하기 (0) | 2022.08.20 |
[iOS] - Responder Chain (0) | 2022.08.04 |