Skip to content

Commit

Permalink
♻️#294: ScrollView 안 CollectionView contentSize 업데이트 이슈로 인해 UITableVi…
Browse files Browse the repository at this point in the history
…ew로 변경 작업 처리

- 기존 Diffable DataSource 로직 변경 없음
- Compositional Layout 제거
  • Loading branch information
thoonk committed Jul 12, 2024
1 parent 29cc826 commit 6f35825
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 113 deletions.
4 changes: 4 additions & 0 deletions StreetDrop/StreetDrop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
6A3AFB582B8DB399003BD144 /* GADUnitID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A3AFB572B8DB399003BD144 /* GADUnitID.swift */; };
6A51EC3C2C3E52FE00DEF6F3 /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC3B2C3E52FE00DEF6F3 /* UIViewController+Rx.swift */; };
6A51EC3E2C3E536000DEF6F3 /* Map+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC3D2C3E536000DEF6F3 /* Map+Rx.swift */; };
6A51EC402C411FB000DEF6F3 /* MusicListTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */; };
6A7D73D92BB11A0E009340E3 /* LevelUpGuideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */; };
6A7D73DD2BB14015009340E3 /* GradientProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */; };
6A7D73DF2BB15826009340E3 /* UIView+RoundCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7D73DE2BB15826009340E3 /* UIView+RoundCorners.swift */; };
Expand Down Expand Up @@ -414,6 +415,7 @@
6A3AFB572B8DB399003BD144 /* GADUnitID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GADUnitID.swift; sourceTree = "<group>"; };
6A51EC3B2C3E52FE00DEF6F3 /* UIViewController+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Rx.swift"; sourceTree = "<group>"; };
6A51EC3D2C3E536000DEF6F3 /* Map+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Map+Rx.swift"; sourceTree = "<group>"; };
6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicListTableView.swift; sourceTree = "<group>"; };
6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelUpGuideView.swift; sourceTree = "<group>"; };
6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientProgressBar.swift; sourceTree = "<group>"; };
6A7D73DE2BB15826009340E3 /* UIView+RoundCorners.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+RoundCorners.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -912,6 +914,7 @@
0856524F2AFBB73100FD9BCB /* MyPageType.swift */,
6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */,
6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */,
6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -1875,6 +1878,7 @@
F4C996A12C1E15CD00FF7B9A /* NoticeListViewController.swift in Sources */,
1867C8202A4DDB8C00F8EC48 /* MyPageViewController.swift in Sources */,
1816ED432A685865005009FC /* NicknameEditModel.swift in Sources */,
6A51EC402C411FB000DEF6F3 /* MusicListTableView.swift in Sources */,
C40008EA2A32012B00EA7FA9 /* Music.swift in Sources */,
413ABEEC2A39D1E900EA1010 /* UIcolor+.swift in Sources */,
41A9BEBB2A4DCBDA00F3605C /* DefaultClaimCommentRepository.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import SnapKit
import RxCocoa
import RxSwift

final class MusicListCell: UICollectionViewCell {
static let identifier = "MusicTableViewCell"
final class MusicListCell: UITableViewCell {
static let identifier = "MusicListCell"
private var disposeBag: DisposeBag = DisposeBag()

override init(frame: CGRect) {
super.init(frame: frame)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)

configureUI()
self.configureUI()
}

@available(*, unavailable)
Expand Down Expand Up @@ -150,6 +150,7 @@ private extension MusicListCell {
// MARK: - Cell

self.backgroundColor = UIColor.gray900
self.selectionStyle = .none

// MARK: - Container StackView

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import UIKit

import SnapKit

final class MusicListSectionHeaderView: UICollectionReusableView {
final class MusicListSectionHeaderView: UITableViewHeaderFooterView {
static let identifier = "MusicListSectionHeaderView"

private lazy var dateLabel: UILabel = {
Expand All @@ -19,10 +19,10 @@ final class MusicListSectionHeaderView: UICollectionReusableView {
return label
}()

override init(frame: CGRect) {
super.init(frame: frame)
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)

configureUI()
self.configureUI()
}

@available(*, unavailable)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// MusicListTableView.swift
// StreetDrop
//
// Created by thoonk on 7/12/24.
//

import UIKit

final class MusicListTableView: UITableView {
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return contentSize
}

override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ import RxSwift
import SnapKit

final class MyPageViewController: UIViewController, Toastable, Alertable {
fileprivate typealias MusicDataSource = UICollectionViewDiffableDataSource<MyMusicsSection, MyMusic>
fileprivate typealias MusicDataSource = UITableViewDiffableDataSource<MyMusicsSection, MyMusic>

private var stickyTapListStackView: UIStackView?
private var stickyTopDimmedView: UIView?

private lazy var musicDataSource: MusicDataSource = configureMusicDataSource()
private var collectionViewHeightConstraint: Constraint?

private var viewModel: MyPageViewModel
private let viewWillAppearEvent = PublishRelay<Void>()
Expand Down Expand Up @@ -187,16 +186,26 @@ final class MyPageViewController: UIViewController, Toastable, Alertable {
return label
}()

private lazy var musicListCollectionView: UICollectionView = {
let collectionView = UICollectionView (
frame: .zero,
collectionViewLayout: createMusicListLayout()
private lazy var musicListTableView: MusicListTableView = {
let tableView = MusicListTableView(frame: .zero, style: .grouped)
tableView.isScrollEnabled = false
tableView.backgroundColor = .clear
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
tableView.delegate = self
tableView.sectionFooterHeight = 0
tableView.separatorStyle = .none

tableView.register(
MusicListCell.self,
forCellReuseIdentifier: MusicListCell.identifier
)
tableView.register(
MusicListSectionHeaderView.self,
forHeaderFooterViewReuseIdentifier: MusicListSectionHeaderView.identifier
)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.isScrollEnabled = false
collectionView.backgroundColor = .clear

return collectionView
return tableView
}()

private lazy var scrollToTopButton: UIButton = {
Expand Down Expand Up @@ -377,15 +386,12 @@ private extension MyPageViewController {

// MARK: - Music List CollectionView

containerView.addSubview(musicListCollectionView)
musicListCollectionView.snp.makeConstraints {
containerView.addSubview(musicListTableView)
musicListTableView.snp.makeConstraints {
$0.top.equalTo(tapListStackView.snp.bottom).offset(8)
$0.leading.trailing.bottom.equalToSuperview()
self.collectionViewHeightConstraint = $0.height.equalTo(1).constraint
}

configureSupplementaryViewRegistration()


// MARK: - Scroll To Top Button

self.view.addSubview(scrollToTopButton)
Expand Down Expand Up @@ -587,7 +593,7 @@ private extension MyPageViewController {
.bind(to: levelPolicyTapEvent)
.disposed(by: disposeBag)

musicListCollectionView.rx.itemSelected
musicListTableView.rx.itemSelected
.throttle(.seconds(2), scheduler: MainScheduler.instance)
.bind(with: self) { owner, indexPath in
guard let item = owner.musicDataSource.itemIdentifier(for: indexPath) else { return }
Expand Down Expand Up @@ -636,7 +642,6 @@ private extension MyPageViewController {

output.myMusicsSections
.bind(with: self) { owner, sections in
owner.updateCollectionViewHeight()
owner.displayMusicList(sections)
}
.disposed(by: disposeBag)
Expand Down Expand Up @@ -759,81 +764,16 @@ private extension MyPageViewController {

private extension MyPageViewController {
func configureMusicDataSource() -> MusicDataSource {
typealias MusicListCellRegistration = UICollectionView.CellRegistration<MusicListCell, MyMusic>

let musicCellRegistration = MusicListCellRegistration { cell, _ , item in
cell.setData(item: item)
}

return MusicDataSource(collectionView: musicListCollectionView) { collectionView, indexPath, item in

return collectionView.dequeueConfiguredReusableCell(
using: musicCellRegistration,
for: indexPath,
item: item
)
}
}

func configureSupplementaryViewRegistration() {
typealias MusicListHeaderRegistration = UICollectionView.SupplementaryRegistration<MusicListSectionHeaderView>

let headerRegistration = MusicListHeaderRegistration(elementKind: UICollectionView.elementKindSectionHeader) { [weak self] headerView, elementKind, indexPath in
guard let self else { return }
return MusicDataSource(tableView: musicListTableView, cellProvider: { tableView, indexPath, item -> UITableViewCell? in
guard let cell = tableView.dequeueReusableCell(
withIdentifier: MusicListCell.identifier,
for: indexPath
) as? MusicListCell else { return nil }

let section = self.musicDataSource.snapshot().sectionIdentifiers[safe: indexPath.section]
if case let .musics(date) = section {
headerView.setData(date: date)
}
}

musicDataSource.supplementaryViewProvider = { [weak self] _, kind, index in
switch kind {
case UICollectionView.elementKindSectionHeader:
return self?.musicListCollectionView.dequeueConfiguredReusableSupplementary(
using: headerRegistration,
for: index
)
default:
return UICollectionReusableView()
}
}
}

func createMusicListLayout() -> UICollectionViewLayout {
return UICollectionViewCompositionalLayout { [weak self] section, env -> NSCollectionLayoutSection? in
guard let self else { return nil }
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(100)
)

let item = NSCollectionLayoutItem(layoutSize: itemSize)

let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(100)
)

let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

let section = NSCollectionLayoutSection(group: group)
let sectionHeader = self.configureSectionHeader()
section.boundarySupplementaryItems = [sectionHeader]
cell.setData(item: item)

return section
}
}

func configureSectionHeader() -> NSCollectionLayoutBoundarySupplementaryItem {
return NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(32)
),
elementKind: UICollectionView.elementKindSectionHeader,
alignment: .top
)
return cell
})
}

func displayMusicList(_ sectionTypes: [MyMusicsSectionType]) {
Expand All @@ -844,21 +784,25 @@ private extension MyPageViewController {
snapshot.appendItems(sectionType.items, toSection: sectionType.section)
}

musicDataSource.apply(snapshot, animatingDifferences: true) { [weak self] in
self?.updateCollectionViewHeight()
musicDataSource.apply(snapshot, animatingDifferences: false)
}
}

// MARK: - UITableViewDelegate

extension MyPageViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let section = self.musicDataSource.snapshot().sectionIdentifiers[safe: section]
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: MusicListSectionHeaderView.identifier) as? MusicListSectionHeaderView

if case let .musics(date) = section {
headerView?.setData(date: date)
}

return headerView
}

func updateCollectionViewHeight() {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.musicListCollectionView.layoutIfNeeded()
let contentHeight = self.musicListCollectionView.contentSize.height
self.collectionViewHeightConstraint?.update(offset: contentHeight)

UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20
}
}

0 comments on commit 6f35825

Please sign in to comment.