Skip to content

Commit 32ece49

Browse files
[FIX] 관리자화면 시트뷰 개선과 디테일뷰로 이동되지않던 이슈 수정및 최적화 (#165)
* refactor/#147: Deletate 분리및 Extension 이동 * refactor/#147: 매직넘버 enum constaranits 분리 * refactor/#156: 관리자페이지에서 디테일뷰로 이동가능 바텀시트뷰 UI 수정 * style/#156: Apply SwiftLint autocorrect --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent f46faf2 commit 32ece49

File tree

6 files changed

+274
-268
lines changed

6 files changed

+274
-268
lines changed

Poppool/PresentationLayer/Presentation/Presentation/Scene/Admin/AdminBottomSheet/AdminBottomSheetReactor.swift

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
//
2-
// AdminBottomSheetReactor.swift
3-
// Poppool
4-
//
5-
// Created by 김기현 on 1/13/25.
6-
//
7-
81
import Foundation
92
import ReactorKit
103

Poppool/PresentationLayer/Presentation/Presentation/Scene/Admin/AdminBottomSheet/AdminBottomSheetView.swift

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import UIKit
2-
31
import DesignSystem
42
import Infrastructure
5-
63
import ReactorKit
74
import RxCocoa
85
import RxSwift
96
import SnapKit
7+
import UIKit
108

119
final class AdminBottomSheetView: UIView {
1210

@@ -39,7 +37,6 @@ final class AdminBottomSheetView: UIView {
3937
let closeButton: UIButton = {
4038
let button = UIButton(type: .system)
4139
button.setImage(UIImage(named: "icon_xmark"), for: .normal)
42-
4340
button.tintColor = .black
4441
return button
4542
}()
@@ -78,16 +75,12 @@ final class AdminBottomSheetView: UIView {
7875
trailing: 20
7976
)
8077
section.interGroupSpacing = 16
81-
8278
return section
8379
}
84-
85-
let collectionView = UICollectionView(
86-
frame: .zero,
87-
collectionViewLayout: layout
88-
)
80+
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
8981
collectionView.backgroundColor = .clear
9082
collectionView.isScrollEnabled = false
83+
// Register cell here if needed, e.g. collectionView.register(TagSectionCell.self, forCellWithReuseIdentifier: TagSectionCell.identifiers)
9184
return collectionView
9285
}()
9386

@@ -102,10 +95,7 @@ final class AdminBottomSheetView: UIView {
10295
)
10396
button.isEnabled = false
10497
button.contentEdgeInsets = UIEdgeInsets(
105-
top: 9,
106-
left: 16,
107-
bottom: 9,
108-
right: 12
98+
top: 9, left: 16, bottom: 9, right: 12
10999
)
110100
return button
111101
}()
@@ -120,10 +110,7 @@ final class AdminBottomSheetView: UIView {
120110
)
121111
button.isEnabled = false
122112
button.contentEdgeInsets = UIEdgeInsets(
123-
top: 9,
124-
left: 16,
125-
bottom: 9,
126-
right: 12
113+
top: 9, left: 16, bottom: 9, right: 12
127114
)
128115
return button
129116
}()
@@ -168,7 +155,7 @@ final class AdminBottomSheetView: UIView {
168155
private func setupConstraints() {
169156
containerView.snp.makeConstraints { make in
170157
make.left.right.bottom.equalToSuperview()
171-
make.top.equalTo(headerView.snp.top)
158+
make.top.equalToSuperview()
172159
}
173160

174161
headerView.snp.makeConstraints { make in
@@ -212,18 +199,40 @@ final class AdminBottomSheetView: UIView {
212199
}
213200

214201
// MARK: - Public Methods
215-
func updateContentVisibility(isCategorySelected: Bool) {
216-
Logger.log("높이 변경 시작: \(isCategorySelected ? "카테고리" : "상태값")", category: .debug)
217-
218-
let newHeight: CGFloat = isCategorySelected ? 200 : 160
219-
220-
// 애니메이션 없이 바로 적용
221-
contentHeightConstraint?.update(offset: newHeight)
222-
contentCollectionView.invalidateIntrinsicContentSize()
223-
224-
setNeedsLayout()
225-
layoutIfNeeded()
202+
func calculateCollectionViewHeight(for items: [String]) -> CGFloat {
203+
let sectionInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
204+
let itemSpacing: CGFloat = 12
205+
let lineSpacing: CGFloat = 16
206+
207+
let collectionViewWidth = UIScreen.main.bounds.width
208+
let availableWidth = collectionViewWidth - sectionInsets.left - sectionInsets.right
209+
210+
var currentRowWidth: CGFloat = 0
211+
var numberOfRows = 1
212+
213+
for (index, item) in items.enumerated() {
214+
let text = item as NSString
215+
let textSize = text.size(withAttributes: [
216+
.font: UIFont.korFont(style: .medium, size: 13)
217+
])
218+
let itemWidth = textSize.width + 32 // padding: 16 left/right each
219+
220+
if index == 0 {
221+
currentRowWidth = itemWidth
222+
} else {
223+
let widthWithSpacing = currentRowWidth + itemSpacing + itemWidth
224+
if widthWithSpacing > availableWidth {
225+
numberOfRows += 1
226+
currentRowWidth = itemWidth
227+
} else {
228+
currentRowWidth = widthWithSpacing
229+
}
230+
}
231+
}
226232

227-
Logger.log("높이 변경 완료", category: .debug)
233+
let itemHeight: CGFloat = 36
234+
return sectionInsets.top + sectionInsets.bottom +
235+
(CGFloat(numberOfRows) * itemHeight) +
236+
(CGFloat(max(0, numberOfRows - 1)) * lineSpacing)
228237
}
229238
}

Poppool/PresentationLayer/Presentation/Presentation/Scene/Admin/AdminBottomSheet/AdminBottomSheetViewController.swift

Lines changed: 93 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
1-
import UIKit
2-
31
import DesignSystem
42
import Infrastructure
5-
63
import ReactorKit
74
import RxCocoa
85
import RxSwift
96
import SnapKit
7+
import UIKit
108

119
final class AdminBottomSheetViewController: BaseViewController, View {
1210

1311
typealias Reactor = AdminBottomSheetReactor
1412

1513
// MARK: - Properties
1614
private let mainView = AdminBottomSheetView()
17-
private let dimmedView = UIView()
15+
private lazy var dimmedView: UIView = {
16+
let view = UIView()
17+
view.backgroundColor = .black.withAlphaComponent(0.4)
18+
view.alpha = 0
19+
return view
20+
}()
1821
var disposeBag = DisposeBag()
1922
private var containerViewBottomConstraint: Constraint?
23+
private var containerHeightConstraint: Constraint?
2024
private var tagSection: TagSection?
2125

2226
var onSave: (([String]) -> Void)?
@@ -43,37 +47,30 @@ final class AdminBottomSheetViewController: BaseViewController, View {
4347
private func setupViews() {
4448
view.backgroundColor = .clear
4549

46-
Logger.log("초기 뷰 계층:", category: .debug)
50+
view.addSubview(dimmedView)
51+
dimmedView.snp.makeConstraints { make in
52+
make.edges.equalToSuperview()
53+
}
4754

4855
view.addSubview(mainView)
49-
mainView.isUserInteractionEnabled = true
50-
mainView.containerView.isUserInteractionEnabled = true
51-
mainView.closeButton.isUserInteractionEnabled = true
52-
mainView.segmentedControl.isUserInteractionEnabled = true
53-
mainView.headerView.isUserInteractionEnabled = true
54-
5556
mainView.snp.makeConstraints { make in
5657
make.left.right.equalToSuperview()
57-
make.height.equalTo(view.bounds.height * 0.45)
58+
containerHeightConstraint = make.height.greaterThanOrEqualTo(400).constraint
5859
containerViewBottomConstraint = make.bottom.equalTo(view.snp.bottom).constraint
5960
}
6061

61-
Logger.log("mainView 추가 후 계층:", category: .debug)
62-
63-
dimmedView.backgroundColor = .black.withAlphaComponent(0.4)
64-
dimmedView.alpha = 0
65-
dimmedView.isUserInteractionEnabled = false
62+
setupGestures()
63+
}
6664

67-
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dimmedViewTapped))
65+
private func setupGestures() {
66+
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapDimmedView))
67+
tapGesture.delegate = self
6868
dimmedView.addGestureRecognizer(tapGesture)
69-
tapGesture.cancelsTouchesInView = true // 터치 이벤트가 다른 뷰로 전달되도록 설정
70-
view.insertSubview(dimmedView, belowSubview: mainView)
71-
72-
dimmedView.snp.makeConstraints { make in
73-
make.edges.equalToSuperview()
74-
}
69+
dimmedView.isUserInteractionEnabled = true
70+
}
7571

76-
Logger.log("최종 뷰 계층:", category: .debug)
72+
@objc private func handleTapDimmedView() {
73+
hideBottomSheet()
7774
}
7875

7976
private func setupCollectionView() {
@@ -86,58 +83,58 @@ final class AdminBottomSheetViewController: BaseViewController, View {
8683
// MARK: - Binding
8784
func bind(reactor: Reactor) {
8885
mainView.segmentedControl.rx.selectedSegmentIndex
89-
.do(onNext: { _ in
90-
})
91-
.map { Reactor.Action.segmentChanged($0) }
92-
.bind(to: reactor.action)
93-
.disposed(by: disposeBag)
86+
.map { Reactor.Action.segmentChanged($0) }
87+
.bind(to: reactor.action)
88+
.disposed(by: disposeBag)
9489

9590
mainView.resetButton.rx.tap
9691
.map { Reactor.Action.resetFilters }
9792
.bind(to: reactor.action)
9893
.disposed(by: disposeBag)
9994

10095
mainView.contentCollectionView.rx.itemSelected
101-
.withLatestFrom(reactor.state) { indexPath, state -> Reactor.Action in
102-
let title = state.activeSegment == 0 ?
103-
state.statusOptions[indexPath.item] :
104-
state.categoryOptions[indexPath.item]
105-
106-
return state.activeSegment == 0 ?
107-
.toggleStatusOption(title) :
108-
.toggleCategoryOption(title)
109-
}
110-
.bind(to: reactor.action)
111-
.disposed(by: disposeBag)
112-
113-
reactor.state.map { state in
114-
let items = state.activeSegment == 0 ?
115-
state.statusOptions :
116-
state.categoryOptions
117-
let selectedItems = state.activeSegment == 0 ?
118-
state.selectedStatusOptions :
119-
state.selectedCategoryOptions
120-
121-
return items.map {
122-
TagSectionCell.Input(
123-
title: $0,
124-
isSelected: selectedItems.contains($0),
125-
id: nil
126-
)
96+
.withLatestFrom(reactor.state) { indexPath, state -> Reactor.Action in
97+
let title = state.activeSegment == 0 ?
98+
state.statusOptions[indexPath.item] :
99+
state.categoryOptions[indexPath.item]
100+
101+
return state.activeSegment == 0 ?
102+
.toggleStatusOption(title) :
103+
.toggleCategoryOption(title)
127104
}
128-
}
129-
.bind(to: mainView.contentCollectionView.rx.items(
130-
cellIdentifier: TagSectionCell.identifiers,
131-
cellType: TagSectionCell.self
132-
)) { _, item, cell in
133-
cell.injection(with: item)
134-
}
135-
.disposed(by: disposeBag)
105+
.bind(to: reactor.action)
106+
.disposed(by: disposeBag)
107+
108+
reactor.state
109+
.map { state in
110+
let items = state.activeSegment == 0 ?
111+
state.statusOptions :
112+
state.categoryOptions
113+
let selectedItems = state.activeSegment == 0 ?
114+
state.selectedStatusOptions :
115+
state.selectedCategoryOptions
116+
117+
return items.map {
118+
TagSectionCell.Input(
119+
title: $0,
120+
isSelected: selectedItems.contains($0),
121+
id: nil
122+
)
123+
}
124+
}
125+
.bind(to: mainView.contentCollectionView.rx.items(
126+
cellIdentifier: TagSectionCell.identifiers,
127+
cellType: TagSectionCell.self
128+
)) { _, item, cell in
129+
cell.injection(with: item)
130+
}
131+
.disposed(by: disposeBag)
136132

133+
// 세그먼트 변경 시 전체 시트 높이 업데이트
137134
reactor.state.map { $0.activeSegment }
138135
.distinctUntilChanged()
139-
.bind { [weak self] index in
140-
self?.mainView.updateContentVisibility(isCategorySelected: index == 1)
136+
.bind { [weak self] _ in
137+
self?.updateContainerHeight()
141138
}
142139
.disposed(by: disposeBag)
143140

@@ -167,7 +164,6 @@ final class AdminBottomSheetViewController: BaseViewController, View {
167164
}
168165
.disposed(by: disposeBag)
169166

170-
// View Events
171167
mainView.closeButton.rx.tap
172168
.bind { [weak self] in
173169
self?.hideBottomSheet()
@@ -189,13 +185,30 @@ final class AdminBottomSheetViewController: BaseViewController, View {
189185
.disposed(by: disposeBag)
190186
}
191187

192-
// MARK: - Actions
193-
@objc private func dimmedViewTapped() {
194-
hideBottomSheet()
188+
// MARK: - Height Management
189+
private func updateContainerHeight() {
190+
guard let reactor = reactor else { return }
191+
192+
let items = reactor.currentState.activeSegment == 0 ?
193+
reactor.currentState.statusOptions :
194+
reactor.currentState.categoryOptions
195+
196+
let collectionViewHeight = mainView.calculateCollectionViewHeight(for: items)
197+
198+
let totalHeight = 60 + 50 + collectionViewHeight + 80 + 52 + 100
199+
200+
let finalHeight = min(max(totalHeight, 400), UIScreen.main.bounds.height * 0.8)
201+
202+
containerHeightConstraint?.update(offset: finalHeight)
203+
204+
self.view.layoutIfNeeded()
195205
}
196206

197207
// MARK: - Show/Hide
198208
func showBottomSheet() {
209+
// 초기 높이 설정
210+
updateContainerHeight()
211+
199212
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut) {
200213
self.dimmedView.alpha = 1
201214
self.containerViewBottomConstraint?.update(offset: 0)
@@ -218,3 +231,13 @@ final class AdminBottomSheetViewController: BaseViewController, View {
218231
Logger.log("BottomSheet deinit", category: .debug)
219232
}
220233
}
234+
235+
extension AdminBottomSheetViewController: UIGestureRecognizerDelegate {
236+
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
237+
if gestureRecognizer.view == dimmedView {
238+
let touchPoint = touch.location(in: view)
239+
return !mainView.containerView.frame.contains(touchPoint)
240+
}
241+
return true
242+
}
243+
}

Poppool/PresentationLayer/Presentation/Presentation/Scene/Admin/AdminView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ final class AdminView: UIView {
9797
override init(frame: CGRect) {
9898
super.init(frame: frame)
9999
setupLayout()
100+
tableView.backgroundView = UIView()
101+
tableView.backgroundView?.isUserInteractionEnabled = true
100102
}
101103

102104
required init?(coder: NSCoder) {

0 commit comments

Comments
 (0)