Skip to content

Commit

Permalink
Merge pull request #236 from TeamChaRo/feature/expended-image-view-in…
Browse files Browse the repository at this point in the history
…-detail

[FEAT] 구경하기 이미지 클릭 시 확대 화면으로 전환
  • Loading branch information
hryeong66 authored Jun 24, 2022
2 parents 51fe18a + 01ad4d0 commit 54cf3f9
Show file tree
Hide file tree
Showing 9 changed files with 333 additions and 106 deletions.
20 changes: 10 additions & 10 deletions ChaRo-iOS/ChaRo-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@
70FD425F2817158900631BB7 /* UpdateProfileService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70FD425E2817158900631BB7 /* UpdateProfileService.swift */; };
70FD4261281715B300631BB7 /* UserDefaultKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70FD4260281715B300631BB7 /* UserDefaultKey.swift */; };
70FD4263281839B400631BB7 /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70FD4262281839B400631BB7 /* String+.swift */; };
7FC2455B2866008A00B3756F /* ExpendedImageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FC2455A2866008A00B3756F /* ExpendedImageVC.swift */; };
7FC2455D2866013000B3756F /* ExpendedImageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FC2455C2866013000B3756F /* ExpendedImageViewModel.swift */; };
8B188860E6B0E2739A7DC8FC /* Pods_ChaRo_iOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A28755551AA4AA1EE63FA224 /* Pods_ChaRo_iOSTests.framework */; };
DDA7344339CF4453CB1007E6 /* Pods_ChaRo_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2D4415326DCA1FAFA4CF005 /* Pods_ChaRo_iOS.framework */; };
F42DA7FD2692235C003DA0DC /* PostTitleDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F42DA7FC2692235C003DA0DC /* PostTitleDataModel.swift */; };
Expand Down Expand Up @@ -490,6 +492,8 @@
70FD425E2817158900631BB7 /* UpdateProfileService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateProfileService.swift; sourceTree = "<group>"; };
70FD4260281715B300631BB7 /* UserDefaultKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultKey.swift; sourceTree = "<group>"; };
70FD4262281839B400631BB7 /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = "<group>"; };
7FC2455A2866008A00B3756F /* ExpendedImageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpendedImageVC.swift; sourceTree = "<group>"; };
7FC2455C2866013000B3756F /* ExpendedImageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpendedImageViewModel.swift; sourceTree = "<group>"; };
83D65C0CC1D310B45627BC8F /* Pods-ChaRo-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChaRo-iOS.release.xcconfig"; path = "Target Support Files/Pods-ChaRo-iOS/Pods-ChaRo-iOS.release.xcconfig"; sourceTree = "<group>"; };
A28755551AA4AA1EE63FA224 /* Pods_ChaRo_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ChaRo_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2D4415326DCA1FAFA4CF005 /* Pods_ChaRo_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ChaRo_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -571,7 +575,6 @@
3CAE519D26C241D300DB8A41 /* MyPageScene */,
3CAE519726C240E100DB8A41 /* OnBoardScene */,
3CAE519C26C241B500DB8A41 /* PostSearchScene */,
36A2FECE278F206800B1D87A /* New Group */,
3610A8912693730700EFC794 /* CommonCVC.swift */,
360937AB2699EF7B005392BB /* TabbarCVC.swift */,
7084948126A23AB7001B3C2B /* CollectionViewFooter.swift */,
Expand Down Expand Up @@ -602,13 +605,6 @@
path = FollowScene;
sourceTree = "<group>";
};
36A2FECE278F206800B1D87A /* New Group */ = {
isa = PBXGroup;
children = (
);
path = "New Group";
sourceTree = "<group>";
};
36B69F7E2775DC0D00FEEAAE /* FollowScene */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1224,6 +1220,7 @@
3CB532CA27C507C2005AAB1D /* Component */,
F49DE532268E148300A8185C /* PostDetailVC.swift */,
3C7A0C4E27CE838100B78854 /* PostLikeListVC.swift */,
7FC2455A2866008A00B3756F /* ExpendedImageVC.swift */,
);
path = PostDetailScene;
sourceTree = "<group>";
Expand Down Expand Up @@ -1419,6 +1416,7 @@
3C7A0C5027CE83AE00B78854 /* PostLikeListViewModel.swift */,
3C86C1BA27DF92CE00A41FCE /* PostDetailViewModel.swift */,
3C34CC7027F19B010016069C /* AddressMainViewModel.swift */,
7FC2455C2866013000B3756F /* ExpendedImageViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -1714,6 +1712,7 @@
3C597C48280EA0CA007153B0 /* UINavigationController+.swift in Sources */,
F42DA80E2694D47F003DA0DC /* PostCourseThemeTVC.swift in Sources */,
F4CC1B65269B943B009A0C01 /* CreatePostPhotoTVC.swift in Sources */,
7FC2455D2866013000B3756F /* ExpendedImageViewModel.swift in Sources */,
3C879BEF268B147D00C41BB8 /* UITableView+.swift in Sources */,
36E445BB277CD6A2008E31BE /* SettingViewDataModel.swift in Sources */,
3C879BF3268B14A800C41BB8 /* UIColor+.swift in Sources */,
Expand Down Expand Up @@ -1800,6 +1799,7 @@
70A37C3126EF5FE3006CCEA9 /* JoinVC.swift in Sources */,
3CB532CF27C50950005AAB1D /* ImageLiterals.swift in Sources */,
7062C84B270CDE6F00C1CD2E /* IsDuplicatedNicknameService.swift in Sources */,
7FC2455B2866008A00B3756F /* ExpendedImageVC.swift in Sources */,
365FEF4927D66C9C0036E182 /* FilterCellView.swift in Sources */,
F4CC1B90269C5EFA009A0C01 /* CreatePostPhotosCVC.swift in Sources */,
3C5B15B82749802600F178A8 /* GenericResponse.swift in Sources */,
Expand Down Expand Up @@ -2045,7 +2045,7 @@
CODE_SIGN_ENTITLEMENTS = "ChaRo-iOS/ChaRo-iOS.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 2ZS26WP93H;
DEVELOPMENT_TEAM = J8A843466G;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
Expand Down Expand Up @@ -2077,7 +2077,7 @@
CODE_SIGN_ENTITLEMENTS = "ChaRo-iOS/ChaRo-iOS.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 2ZS26WP93H;
DEVELOPMENT_TEAM = JCV986BPR5;
"EXCLUDED_ARCHS[sdk=*]" = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand Down
5 changes: 0 additions & 5 deletions ChaRo-iOS/ChaRo-iOS.xcworkspace/appleLogo.svg

This file was deleted.

39 changes: 39 additions & 0 deletions ChaRo-iOS/ChaRo-iOS/Source/ViewModels/ExpendedImageViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// ExpendedImageViewModel.swift
// ChaRo-iOS
//
// Created by 장혜령 on 2022/06/24.
//

import Foundation
import RxSwift

class ExpendedImageViewModel {

private let dismissibleHeight: CGFloat = 300
private let newHeightSubject = PublishSubject<CGFloat?>()

struct Input {
let scrolledOffsetSubject: PublishSubject<CGFloat>
}

struct Output {
let newHeightSubject: PublishSubject<CGFloat?>
}

func transform(to input: Input, disposeBag: DisposeBag) -> Output {
input.scrolledOffsetSubject.bind(onNext: { [weak self] yOffset in
let newHeight = self?.calculateNewHeight(with: yOffset)
self?.newHeightSubject.onNext(newHeight)
}).disposed(by: disposeBag)
return Output(newHeightSubject: newHeightSubject)
}

private func calculateNewHeight(with yOffset: CGFloat) -> CGFloat? {
if yOffset > 0 {
return yOffset > dismissibleHeight ? -1 : yOffset
}
return nil
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Then

final class PostPhotoCVC: UICollectionViewCell{

private let imageView = UIImageView().then {
let imageView = UIImageView().then {
$0.contentMode = .scaleAspectFill
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import RxSwift
final class PostPhotoTVC: UITableViewCell{

// MARK: - properties
var presentingClosure: (() -> ())?

private let disposeBag = DisposeBag()
private let photoSubject = PublishSubject<[String]>()
Expand Down Expand Up @@ -77,6 +78,10 @@ final class PostPhotoTVC: UITableViewCell{
cellType: PostPhotoCVC.self)) { row, element, cell in
cell.setImage(to: element)
}.disposed(by: disposeBag)

collectionView.rx.itemSelected.bind(onNext: { [weak self] indexPath in
self?.presentingClosure?()
})
}

func setContent(imageList: [String]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//
// ExpendedImageVC.swift
// ChaRo-iOS
//
// Created by 장혜령 on 2022/06/24.
//

import UIKit
import SnapKit
import Then
import RxSwift

final class ExpendedImageVC: UIViewController {

// MARK: - properties
private let disposeBag = DisposeBag()
private let imageList: [String]
private let animator = UIViewPropertyAnimator(duration: 0.4, curve: .easeInOut)
private let scrolledOffsetSubject = PublishSubject<CGFloat>()
private let photoSubject = ReplaySubject<[String]>.create(bufferSize: 1)

private let xmarkButton = UIButton().then {
$0.setImage(ImageLiterals.icCloseWhite, for: .normal)
}

private lazy var photoNumberButton = UIButton().then {
$0.titleLabel?.font = .notoSansMediumFont(ofSize: 15)
$0.setTitleColor(.white, for: .normal)
$0.setTitle("1 / \(imageList.count)", for: .normal)
$0.layer.cornerRadius = 25.0 / 2.0
$0.backgroundColor = .gray10.withAlphaComponent(0.7)
}

private lazy var collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()).then {
let layout = UICollectionViewFlowLayout()
let screenWidth = UIScreen.main.bounds.width
layout.itemSize = CGSize(width: screenWidth, height: UIScreen.main.bounds.height)
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.scrollDirection = .horizontal
$0.setCollectionViewLayout(layout, animated: true)
$0.tintColor = .clear
$0.backgroundColor = .clear
$0.register(cell: PostPhotoCVC.self)
$0.rx.setDelegate(self)
$0.showsHorizontalScrollIndicator = false
$0.isPagingEnabled = true
}

private let viewModel: ExpendedImageViewModel

init(imageList: [String]) {
self.imageList = imageList
self.photoSubject.onNext(imageList)
self.viewModel = ExpendedImageViewModel()
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
bind()
render()
configUI()
}

private func render() {
view.addSubviews([collectionView, xmarkButton, photoNumberButton])
collectionView.snp.makeConstraints {
$0.top.bottom.equalTo(view.safeAreaLayoutGuide)
$0.leading.trailing.equalToSuperview()
}

xmarkButton.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide).offset(11)
$0.trailing.equalToSuperview().inset(10)
$0.width.height.equalTo(50)
}

photoNumberButton.snp.makeConstraints {
$0.centerX.equalToSuperview()
$0.bottom.equalTo(view.safeAreaLayoutGuide).inset(20)
$0.width.equalTo(61)
$0.height.equalTo(25)
}
}

private func configUI() {
view.backgroundColor = .black.withAlphaComponent(0.9)
setupPanGesture()
}

private func setupPanGesture() {
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(gesture:)))
panGesture.delegate = self
view.addGestureRecognizer(panGesture)
}

@objc
private func handlePanGesture(gesture: UIPanGestureRecognizer) {
let transtionY = gesture.translation(in: view).y
switch gesture.state{
case .changed:
scrolledOffsetSubject.onNext(transtionY)
case .ended:
animateContainerView(yOffset: 0)
default:
break
}
}

private func animateContainerView(yOffset: CGFloat) {
collectionView.snp.updateConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide).offset(yOffset)
}
}

private func animateDismissView() {
animator.addAnimations {
self.view.backgroundColor = .clear
self.collectionView.alpha = 0
}
animator.addCompletion { _ in
self.dismiss(animated: false)
}
animator.startAnimation()
}

private func bind() {
photoSubject
.bind(to: collectionView.rx.items(cellIdentifier: PostPhotoCVC.className,
cellType: PostPhotoCVC.self)) { row, element, cell in
cell.imageView.contentMode = .scaleAspectFit
cell.setImage(to: element)
}.disposed(by: disposeBag)

xmarkButton.rx.tap
.asDriver()
.drive(onNext: { [weak self] _ in
self?.dismiss(animated: true, completion: nil)
}).disposed(by: disposeBag)

bindToViewModel()
}

private func bindToViewModel() {
let output = viewModel.transform(to: ExpendedImageViewModel.Input(scrolledOffsetSubject: scrolledOffsetSubject), disposeBag: disposeBag)
output.newHeightSubject
.filter { $0 != nil }
.bind(onNext: { yoffset in
yoffset == -1 ? self.animateDismissView() : self.animateContainerView(yOffset: yoffset ?? 0)
}).disposed(by: disposeBag)
}
}

extension ExpendedImageVC: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}

extension ExpendedImageVC: UICollectionViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
photoNumberButton.setTitle("\(currentPage + 1) / \(imageList.count)", for: .normal)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,13 @@ extension PostDetailVC: UITableViewDataSource {

case 1:
guard let cell = tableView.dequeueReusableCell(withType: PostPhotoTVC.self, for: indexPath) else { return UITableViewCell() }
cell.setContent(imageList: [additionalData.image] + postData.images)
let imageList = [additionalData.image] + postData.images
cell.setContent(imageList: imageList)
cell.presentingClosure = { [weak self] in
let nextVC = ExpendedImageVC(imageList: imageList)
nextVC.modalPresentationStyle = .fullScreen
self?.present(nextVC, animated: true)
}
return cell

case 2:
Expand Down
5 changes: 5 additions & 0 deletions ChaRo-iOS/ChaRo-iOS/Source/Views/VCs/SignScene/LoginVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ class LoginVC: UIViewController {
configureLoginButtonUI()
configureTextfieldUI()
configureNotificationCenter()
addTestUserAccount()
}

private func addTestUserAccount() {
self.idTextField.text = "[email protected]"
self.pwdTextField.text = "charo0505"
}
override func viewDidDisappear(_ animated: Bool) {
removeObservers()
}
Expand Down
Loading

0 comments on commit 54cf3f9

Please sign in to comment.