Skip to content

Commit

Permalink
Merge pull request #6 from croquiscom/feature/APP-7009-affiliate
Browse files Browse the repository at this point in the history
APP-7009 어필레이트 뷰 구현을 위한 CustomTopView 구현
  • Loading branch information
Hyunsik-Yoo authored Jun 13, 2023
2 parents 28a5cb2 + 8c20140 commit c9fb501
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 8 deletions.
2 changes: 1 addition & 1 deletion PanModal.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'PanModal'
s.version = '1.4.9'
s.version = '1.5.0'
s.summary = 'PanModal is an elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.'

# This description is used to generate tags and improve search results.
Expand Down
30 changes: 26 additions & 4 deletions PanModal/Animator/PanModalPresentationAnimator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,25 @@ public class PanModalPresentationAnimator: NSObject {

// Use panView as presentingView if it already exists within the containerView
let panView: UIView = transitionContext.containerView.panContainerView ?? toVC.view

let topView = transitionContext.containerView.panCustomTopView
let topViewHeight: CGFloat = {
if let topViewHeight = topView?.frame.height {
return topViewHeight + PanModalPresentationController.Constants.customTopViewOffset
} else {
return 0
}
}()

// Move presented view offscreen (from the bottom)
panView.frame = transitionContext.finalFrame(for: toVC)
panView.frame.origin.y = transitionContext.containerView.frame.height
panView.frame.origin.y = transitionContext.containerView.frame.height + topViewHeight
topView?.alpha = 0
topView?.frame.origin.y = transitionContext.containerView.frame.height

PanModalAnimator.animate({
panView.frame.origin.y = yPos
topView?.frame.origin.y = yPos - topViewHeight
topView?.alpha = 1
}, config: presentable) { didComplete in
transitionContext.completeTransition(didComplete)
}
Expand All @@ -82,9 +94,19 @@ public class PanModalPresentationAnimator: NSObject {

let presentable = fromVC as? PanModalPresentable.LayoutType
let panView: UIView = transitionContext.containerView.panContainerView ?? fromVC.view

let topView = transitionContext.containerView.panCustomTopView
let topViewHeight: CGFloat = {
if let topViewHeight = topView?.frame.height {
return topViewHeight + PanModalPresentationController.Constants.customTopViewOffset
} else {
return 0
}
}()

PanModalAnimator.animate({
panView.frame.origin.y = transitionContext.containerView.frame.height + PanModalPresentationController.Constants.dragIndicatorHeight
panView.frame.origin.y = transitionContext.containerView.frame.height + PanModalPresentationController.Constants.dragIndicatorHeight + topViewHeight
topView?.frame.origin.y = transitionContext.containerView.frame.height
topView?.alpha = 0.0
}, config: presentable) { didComplete in
fromVC.view.removeFromSuperview()
transitionContext.completeTransition(didComplete)
Expand Down
26 changes: 25 additions & 1 deletion PanModal/Controller/PanModalPresentationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class PanModalPresentationController: UIPresentationController {
struct Constants {
static let snapMovementSensitivity = CGFloat(0.7)
static let dragIndicatorHeight = CGFloat(16)
static let customTopViewOffset = CGFloat(10)
}

// MARK: - Properties
Expand Down Expand Up @@ -204,6 +205,7 @@ public class PanModalPresentationController: UIPresentationController {
override public func presentationTransitionDidEnd(_ completed: Bool) {
if completed { return }

presentable?.panCustomTopView?.removeFromSuperview()
backgroundView.removeFromSuperview()
}

Expand Down Expand Up @@ -339,6 +341,8 @@ private extension PanModalPresentationController {
if presentable.showDragIndicator {
addDragIndicatorView(to: presentedView)
}

addCustomTopViewIfExisted(in: containerView)

setNeedsLayoutUpdate()
adjustPanContainerBackgroundColor()
Expand Down Expand Up @@ -379,7 +383,18 @@ private extension PanModalPresentationController {
backgroundView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
backgroundView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
}



func addCustomTopViewIfExisted(in containerView: UIView) {
guard let customTopView = presentable?.panCustomTopView else { return }
containerView.addSubview(customTopView)
customTopView.translatesAutoresizingMaskIntoConstraints = false
customTopView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
customTopView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
customTopView.bottomAnchor.constraint(equalTo: dragIndicatorView.topAnchor, constant: -Constants.customTopViewOffset).isActive = true
customTopView.heightAnchor.constraint(equalToConstant: customTopView.frame.height).isActive = true
}

/**
Adds the drag indicator view to the view hierarchy
& configures its layout constraints.
Expand Down Expand Up @@ -629,7 +644,16 @@ private extension PanModalPresentationController {
Sets the y position of the presentedView & adjusts the backgroundView.
*/
func adjust(toYPosition yPos: CGFloat) {
let topViewHeight: CGFloat = {
if let topViewHeight = presentable?.panCustomTopView?.frame.height {
return topViewHeight + Constants.customTopViewOffset
} else {
return 0
}
}()

presentedView.frame.origin.y = max(yPos, anchoredYPosition)
presentable?.panCustomTopView?.frame.origin.y = max(yPos, anchoredYPosition) - topViewHeight - PanModalPresentationController.Constants.dragIndicatorHeight

guard presentedView.frame.origin.y > shortFormYPosition else {
backgroundView.dimState = .max
Expand Down
12 changes: 11 additions & 1 deletion PanModal/Controller/PanModalWrappedViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class PanModalWrappedViewController: UIViewController {
struct Constants {
static let snapMovementSensitivity = CGFloat(0.7)
static let dragIndicatorHeight = CGFloat(16)
static let customTopViewOffset = CGFloat(10)
}

// MARK: - Properties
Expand Down Expand Up @@ -607,8 +608,17 @@ private extension PanModalWrappedViewController {
Sets the y position of the presentedView & adjusts the backgroundView.
*/
func adjust(toYPosition yPos: CGFloat) {
let topViewHeight: CGFloat = {
if let topViewHeight = presentable?.panCustomTopView?.frame.height {
return topViewHeight + Constants.customTopViewOffset
} else {
return 0
}
}()

presentedView.frame.origin.y = max(yPos, anchoredYPosition)

presentable?.panCustomTopView?.frame.origin.y = max(yPos, anchoredYPosition) - topViewHeight - PanModalPresentationController.Constants.dragIndicatorHeight

guard presentedView.frame.origin.y > shortFormYPosition else {
backgroundView.dimState = .max
return
Expand Down
4 changes: 4 additions & 0 deletions PanModal/Presentable/PanModalPresentable+Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ public extension PanModalPresentable where Self: UIViewController {
var showDragIndicator: Bool {
return true
}

var panCustomTopView: PanCustomTopView? {
return nil
}

func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool {
return true
Expand Down
4 changes: 3 additions & 1 deletion PanModal/Presentable/PanModalPresentable+LayoutHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ extension PanModalPresentable where Self: UIViewController {

}

return container.bounds.size.height - topOffset
let customTopViewHeight = panCustomTopView?.frame.height ?? 0

return container.bounds.size.height - topOffset - customTopViewHeight
}

/**
Expand Down
2 changes: 2 additions & 0 deletions PanModal/Presentable/PanModalPresentable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ public protocol PanModalPresentable {
*/
var showDragIndicator: Bool { get }

var panCustomTopView: PanCustomTopView? { get }

/**
Asks the delegate if the pan modal should respond to the pan modal gesture recognizer.

Expand Down
11 changes: 11 additions & 0 deletions PanModal/View/CustomTopView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import UIKit

open class PanCustomTopView: UIView {

}

extension UIView {
var panCustomTopView: PanCustomTopView? {
return subviews.compactMap({ $0 as? PanCustomTopView }).first
}
}
6 changes: 6 additions & 0 deletions PanModalDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
638A9380256B4DC500A5E00B /* PanModalWrappedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A937F256B4DC500A5E00B /* PanModalWrappedViewController.swift */; };
638A9383256B4E3F00A5E00B /* PanModalWrappedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A937F256B4DC500A5E00B /* PanModalWrappedViewController.swift */; };
638A938D256BB26E00A5E00B /* EmbedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A9387256BB21800A5E00B /* EmbedViewController.swift */; };
6E763B4C2A2E2313002A77E8 /* CustomTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E763B4B2A2E2313002A77E8 /* CustomTopView.swift */; };
6E763B4D2A2E25A2002A77E8 /* CustomTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E763B4B2A2E2313002A77E8 /* CustomTopView.swift */; };
743CABB02225FC9F00634A5A /* UserGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABAF2225FC9F00634A5A /* UserGroupViewController.swift */; };
743CABB22225FD1100634A5A /* UserGroupHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABB12225FD1100634A5A /* UserGroupHeaderView.swift */; };
743CABB42225FE7700634A5A /* UserGroupMemberPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABB32225FE7700634A5A /* UserGroupMemberPresentable.swift */; };
Expand Down Expand Up @@ -99,6 +101,7 @@
0F2A2C542239C119003BDB2F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
638A937F256B4DC500A5E00B /* PanModalWrappedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalWrappedViewController.swift; sourceTree = "<group>"; };
638A9387256BB21800A5E00B /* EmbedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbedViewController.swift; sourceTree = "<group>"; };
6E763B4B2A2E2313002A77E8 /* CustomTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTopView.swift; sourceTree = "<group>"; };
743CABAF2225FC9F00634A5A /* UserGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupViewController.swift; sourceTree = "<group>"; };
743CABB12225FD1100634A5A /* UserGroupHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupHeaderView.swift; sourceTree = "<group>"; };
743CABB32225FE7700634A5A /* UserGroupMemberPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupMemberPresentable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -321,6 +324,7 @@
DC13906E216D9458007A3E64 /* DimmedView.swift */,
94795C9C21F03368008045A0 /* PanContainerView.swift */,
D134CC7022641B350022AA29 /* IndicatorView.swift */,
6E763B4B2A2E2313002A77E8 /* CustomTopView.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -541,6 +545,7 @@
0F2A2C622239C148003BDB2F /* PanModalHeight.swift in Sources */,
0F2A2C632239C14B003BDB2F /* PanModalPresentable.swift in Sources */,
0F2A2C642239C14E003BDB2F /* PanModalPresentable+Defaults.swift in Sources */,
6E763B4C2A2E2313002A77E8 /* CustomTopView.swift in Sources */,
0F2A2C652239C151003BDB2F /* PanModalPresentable+UIViewController.swift in Sources */,
0F2A2C662239C153003BDB2F /* PanModalPresentable+LayoutHelpers.swift in Sources */,
0F2A2C672239C157003BDB2F /* PanModalPresenter.swift in Sources */,
Expand Down Expand Up @@ -587,6 +592,7 @@
DC139061216D93ED007A3E64 /* SampleViewController.swift in Sources */,
743CABB02225FC9F00634A5A /* UserGroupViewController.swift in Sources */,
638A938D256BB26E00A5E00B /* EmbedViewController.swift in Sources */,
6E763B4D2A2E25A2002A77E8 /* CustomTopView.swift in Sources */,
DCC0EE7C21917F2500208DBC /* PanModalPresentable+Defaults.swift in Sources */,
94795C9D21F03368008045A0 /* PanContainerView.swift in Sources */,
74C072A7220BA78800124CE1 /* PanModalPresentable+LayoutHelpers.swift in Sources */,
Expand Down
60 changes: 60 additions & 0 deletions Sample/View Controllers/BasicViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import UIKit

class BasicViewController: UIViewController {
private let topView = TopView()

override func viewDidLoad() {
super.viewDidLoad()
Expand All @@ -33,4 +34,63 @@ extension BasicViewController: PanModalPresentable {
var anchorModalToLongForm: Bool {
return false
}

var panCustomTopView: PanCustomTopView? {
return topView
}
}

extension BasicViewController {
final class TopView: PanCustomTopView {
enum Layout {
static let size = CGSize(width: UIScreen.main.bounds.width, height: 50)
}

private let containerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .white
containerView.layer.cornerRadius = 12
containerView.layer.masksToBounds = true

return containerView
}()

private let affiliateSwitch = UISwitch()

private let titleLabel: UILabel = {
let label = UILabel()
label.text = "CustomTopView Example"
label.textColor = .black
return label
}()

override init(frame: CGRect) {
super.init(frame: .init(origin: .zero, size: Layout.size))

setupUI()
}

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

private func setupUI() {
containerView.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

containerView.addSubview(affiliateSwitch)
affiliateSwitch.translatesAutoresizingMaskIntoConstraints = false
affiliateSwitch.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 10).isActive = true
affiliateSwitch.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16).isActive = true
containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16).isActive = true
containerView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
}

0 comments on commit c9fb501

Please sign in to comment.