├── .gitignore ├── Images └── sample.gif ├── LICENSE ├── README.md └── SemiModalSample ├── SemiModal ├── Info.plist ├── SemiModal.h ├── SemiModalDismissAnimatedTransition.swift ├── SemiModalDismissInteractiveTransition.swift ├── SemiModalIndicatorView.swift ├── SemiModalOverlayView.swift ├── SemiModalPresentationController.swift └── SemiModalPresenter.swift ├── SemiModalSample.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── SemiModalSample ├── Application ├── AppDelegate.swift └── SceneDelegate.swift ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── Info.plist └── Presentation ├── LaunchScreen └── Base.lproj │ └── LaunchScreen.storyboard ├── Main ├── Base.lproj │ └── Main.storyboard └── MainViewController.swift └── Modal ├── ModalViewController.storyboard └── ModalViewController.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # https://github.com/github/gitignore/blob/master/Global/Xcode.gitignore 2 | # Xcode 3 | # 4 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 5 | 6 | ## User settings 7 | xcuserdata/ 8 | 9 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 10 | *.xcscmblueprint 11 | *.xccheckout 12 | 13 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 14 | build/ 15 | DerivedData/ 16 | *.moved-aside 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | 26 | ## Gcc Patch 27 | /*.gcno -------------------------------------------------------------------------------- /Images/sample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fablic/ios_semi_modal_sample/343a1611052767bc3ce87b9adec931b7f101e7ff/Images/sample.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rakuma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SemiModalSample 2 | 3 | iOS semi-modal / half-modal implementation sample 4 | 5 | ![sample](./Images/sample.gif) -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModal.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | #import 6 | 7 | //! Project version number for SemiModal. 8 | FOUNDATION_EXPORT double SemiModalVersionNumber; 9 | 10 | //! Project version string for SemiModal. 11 | FOUNDATION_EXPORT const unsigned char SemiModalVersionString[]; 12 | 13 | // In this header, you should import all the public headers of your framework using statements like #import 14 | 15 | 16 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModalDismissAnimatedTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /// セミモーダルのdismissのアニメーター 8 | final class SemiModalDismissAnimatedTransition: NSObject { 9 | } 10 | 11 | // MARK: - UIViewControllerAnimatedTransitioning 12 | extension SemiModalDismissAnimatedTransition: UIViewControllerAnimatedTransitioning { 13 | 14 | /// transitionの時間 15 | /// - Parameter transitionContext: 16 | /// - Returns: 17 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 18 | return 0.4 19 | } 20 | 21 | /// アニメーションtransition 22 | /// - Parameter transitionContext: 23 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 24 | UIView.animate( 25 | withDuration: transitionDuration(using: transitionContext), 26 | delay: 0.0, 27 | options: .curveEaseInOut, 28 | animations: { 29 | guard let fromView = transitionContext.view(forKey: .from) else { return } 30 | // Viewを下にスライドさせる 31 | fromView.center.y = UIScreen.main.bounds.size.height + fromView.bounds.height / 2 32 | }, 33 | completion: { _ in 34 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 35 | } 36 | ) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModalDismissInteractiveTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /// セミモーダルのインタラクティブなdismiss transition制御 8 | final class SemiModalDismissInteractiveTransition: UIPercentDrivenInteractiveTransition { 9 | 10 | // MARK: Private Properties 11 | 12 | /// 表示しているViewController 13 | weak var viewController: UIViewController? 14 | 15 | /// 遷移中かどうか 16 | private(set) var isInteractiveDismalTransition = false 17 | 18 | /// 完了閾値(0 ~ 1.0) 19 | private let percentCompleteThreshold: CGFloat = 0.3 20 | 21 | /// ジェスチャーの方向 22 | private var gestureDirection = GestureDirection.down 23 | 24 | // MARK: Override functions 25 | 26 | override func cancel() { 27 | completionSpeed = self.percentCompleteThreshold 28 | super.cancel() 29 | } 30 | 31 | override func finish() { 32 | completionSpeed = 1.0 - self.percentCompleteThreshold 33 | super.finish() 34 | } 35 | } 36 | 37 | // MARK: - Pan Gesture 38 | extension SemiModalDismissInteractiveTransition { 39 | 40 | /// ジェスチャーの方向 41 | enum GestureDirection { 42 | case up 43 | case down 44 | 45 | init(recognizer: UIPanGestureRecognizer, view: UIView) { 46 | let velocity = recognizer.velocity(in: view) 47 | self = velocity.y <= 0 ? .up : .down 48 | } 49 | } 50 | 51 | /// Panジェスチャーをつける 52 | /// - Parameter viewController: 対象のViewController 53 | func addPanGesture(to views: [UIView]) { 54 | views.forEach { 55 | let panGesture = UIPanGestureRecognizer(target: self, action: #selector(dismissalPanGesture(recognizer:))) 56 | panGesture.delegate = self 57 | $0.addGestureRecognizer(panGesture) 58 | } 59 | } 60 | 61 | /// Panジェスチャー 62 | /// - Parameter recognizer: 63 | @objc private func dismissalPanGesture(recognizer: UIPanGestureRecognizer) { 64 | guard let viewController = viewController else { return } 65 | 66 | isInteractiveDismalTransition = recognizer.state == .began || recognizer.state == .changed 67 | 68 | switch recognizer.state { 69 | case .began: 70 | gestureDirection = GestureDirection(recognizer: recognizer, view: viewController.view) 71 | if gestureDirection == .down { 72 | viewController.dismiss(animated: true, completion: nil) 73 | } 74 | case .changed: 75 | // インタラクティブな制御のために、Viewの高さに応じた画面更新を行う 76 | let translation = recognizer.translation(in: viewController.view) 77 | var progress = translation.y / viewController.view.bounds.size.height 78 | switch gestureDirection { 79 | case .up: 80 | progress = -max(-1.0, max(-1.0, progress)) 81 | case .down: 82 | progress = min(1.0, max(0, progress)) 83 | } 84 | update(progress) 85 | case .cancelled, .ended: 86 | if percentComplete > percentCompleteThreshold { 87 | finish() 88 | } else { 89 | cancel() 90 | } 91 | default: 92 | break 93 | } 94 | } 95 | } 96 | 97 | // MARK: - UIGestureRecognizerDelegate 98 | extension SemiModalDismissInteractiveTransition: UIGestureRecognizerDelegate { 99 | 100 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 101 | // UIScrollViewのときはpan gestureとコンフリクトしないようにする 102 | if otherGestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer.view is UIScrollView { 103 | return true 104 | } else { 105 | return false 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModalIndicatorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /// セミモーダルインジケータ 8 | final class SemiModalIndicatorView: UIView { 9 | 10 | // MARK: Initializer 11 | 12 | required init?(coder aDecoder: NSCoder) { 13 | super.init(coder: aDecoder) 14 | setup() 15 | } 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | setup() 20 | } 21 | } 22 | 23 | // MARK: Private Functions 24 | extension SemiModalIndicatorView { 25 | 26 | private func setup() { 27 | layer.masksToBounds = true 28 | layer.cornerRadius = 5.0 29 | backgroundColor = UIColor.lightGray 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModalOverlayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /// セミモーダルオーバーレイ 8 | final class SemiModalOverlayView: UIView { 9 | 10 | // MARK: Public Properties 11 | 12 | var isActive: Bool = false { 13 | didSet { 14 | alpha = isActive ? 0.5 : 0.0 15 | } 16 | } 17 | 18 | // MARK: Initializer 19 | 20 | required init?(coder aDecoder: NSCoder) { 21 | super.init(coder: aDecoder) 22 | setup() 23 | } 24 | 25 | override init(frame: CGRect) { 26 | super.init(frame: frame) 27 | setup() 28 | } 29 | } 30 | 31 | // MARK: - Private Functions 32 | extension SemiModalOverlayView { 33 | 34 | private func setup() { 35 | backgroundColor = UIColor.black 36 | alpha = 0.5 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModalPresentationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /// セミモーダル表示のレイアウト実装 8 | final class SemiModalPresentationController: UIPresentationController { 9 | 10 | // MARK: Override Properties 11 | 12 | /// 表示transitionの終わりのViewのframe 13 | override var frameOfPresentedViewInContainerView: CGRect { 14 | guard let containerView = containerView else { return CGRect.zero } 15 | var presentedViewFrame = CGRect.zero 16 | let containerBounds = containerView.bounds 17 | presentedViewFrame.size = self.size(forChildContentContainer: self.presentedViewController, withParentContainerSize: containerBounds.size) 18 | presentedViewFrame.origin.x = containerBounds.size.width - presentedViewFrame.size.width 19 | presentedViewFrame.origin.y = containerBounds.size.height - presentedViewFrame.size.height 20 | return presentedViewFrame 21 | } 22 | 23 | // MARK: Private Properties 24 | 25 | /// オーバーレイ 26 | private let overlay: SemiModalOverlayView 27 | 28 | /// インジケータ 29 | private let indicator: SemiModalIndicatorView 30 | 31 | /// セミモーダルの高さのデフォルト比率 32 | private let presentedViewControllerHeightRatio: CGFloat = 0.5 33 | 34 | // MARK: Initializer 35 | 36 | init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?, overlayView: SemiModalOverlayView, indicator: SemiModalIndicatorView) { 37 | self.overlay = overlayView 38 | self.indicator = indicator 39 | super.init(presentedViewController: presentedViewController, presenting: presentingViewController) 40 | } 41 | 42 | // MARK: Override Functions 43 | 44 | /// 表示されるViewのサイズ 45 | /// - Parameters: 46 | /// - container: コンテナ 47 | /// - parentSize: 親Viewのサイズ 48 | /// - Returns: サイズ 49 | override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize { 50 | // delegateで高さが指定されていれば、そちらを優先する 51 | if let delegate = presentedViewController as? SemiModalPresenterDelegate { 52 | return CGSize(width: parentSize.width, height: delegate.semiModalContentHeight) 53 | } 54 | // 上記でなければ、高さは比率で計算する 55 | return CGSize(width: parentSize.width, height: parentSize.height * self.presentedViewControllerHeightRatio) 56 | } 57 | 58 | /// Subviewsのレイアウト 59 | override func containerViewWillLayoutSubviews() { 60 | guard let containerView = containerView else { return } 61 | 62 | // overlay 63 | // containerViewと同じ大きさで、一番上のレイヤーに挿入する 64 | overlay.frame = containerView.bounds 65 | containerView.insertSubview(overlay, at: 0) 66 | 67 | // presentedView 68 | // frameの大きさ設定、左上と右上を角丸にする 69 | presentedView?.frame = frameOfPresentedViewInContainerView 70 | presentedView?.layer.cornerRadius = 10.0 71 | presentedView?.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] 72 | 73 | // indicator 74 | // 中央上部に配置する 75 | indicator.frame = CGRect(x: 0, y: 0, width: 60, height: 8) 76 | presentedViewController.view.addSubview(indicator) 77 | indicator.translatesAutoresizingMaskIntoConstraints = false 78 | NSLayoutConstraint.activate([ 79 | indicator.centerXAnchor.constraint(equalTo: presentedViewController.view.centerXAnchor), 80 | indicator.topAnchor.constraint(equalTo: presentedViewController.view.topAnchor, constant: -16), 81 | indicator.widthAnchor.constraint(equalToConstant: indicator.frame.width), 82 | indicator.heightAnchor.constraint(equalToConstant: indicator.frame.height) 83 | ]) 84 | } 85 | 86 | /// presentation transition 開始 87 | override func presentationTransitionWillBegin() { 88 | presentedViewController.transitionCoordinator?.animate(alongsideTransition: { _ in 89 | self.overlay.isActive = true 90 | }, completion: nil) 91 | } 92 | 93 | /// dismiss transition 開始 94 | override func dismissalTransitionWillBegin() { 95 | self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { _ in 96 | self.overlay.isActive = false 97 | }, completion: nil) 98 | } 99 | 100 | /// dismiss transition 終了 101 | /// - Parameter completed: 102 | override func dismissalTransitionDidEnd(_ completed: Bool) { 103 | if completed { 104 | overlay.removeFromSuperview() 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModal/SemiModalPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | public protocol SemiModalPresenterDelegate: AnyObject { 8 | 9 | /// ViewControllerからモーダルの高さを決定させる場合に使用する 10 | var semiModalContentHeight: CGFloat { get } 11 | } 12 | 13 | /// ViewControllerをセミモーダルで表示する 14 | public final class SemiModalPresenter: NSObject { 15 | 16 | // MARK: Public Properties 17 | 18 | /// presentするViewControllerを設定する 19 | public weak var viewController: UIViewController? { 20 | didSet { 21 | if let viewController = viewController { 22 | viewController.modalPresentationStyle = .custom 23 | viewController.transitioningDelegate = self 24 | dismissInteractiveTransition.viewController = viewController 25 | dismissInteractiveTransition.addPanGesture(to: [viewController.view, indicator, overlayView]) 26 | } 27 | } 28 | } 29 | 30 | // MARK: Private Properties 31 | 32 | /// オーバーレイ 33 | private lazy var overlayView: SemiModalOverlayView = { 34 | let overlayView = SemiModalOverlayView() 35 | overlayView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(overlayDidTap(_:)))) 36 | return overlayView 37 | }() 38 | 39 | /// モーダル上部に設置されるインジケータ 40 | private lazy var indicator: SemiModalIndicatorView = { 41 | let indicator = SemiModalIndicatorView() 42 | indicator.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(indicatorDidTap(_:)))) 43 | return indicator 44 | }() 45 | 46 | /// インタラクティブなdismiss transition 47 | private let dismissInteractiveTransition = SemiModalDismissInteractiveTransition() 48 | } 49 | 50 | // MARK: - Gestures 51 | extension SemiModalPresenter { 52 | 53 | /// オーバーレイタップ 54 | /// - Parameter sender: 55 | @objc private func overlayDidTap(_ sender: AnyObject) { 56 | viewController?.dismiss(animated: true, completion: nil) 57 | } 58 | 59 | /// インジケータタップ 60 | /// - Parameter sender: 61 | @objc private func indicatorDidTap(_ sender: AnyObject) { 62 | viewController?.dismiss(animated: true, completion: nil) 63 | } 64 | } 65 | 66 | // MARK: - UIViewControllerTransitioningDelegate 67 | extension SemiModalPresenter: UIViewControllerTransitioningDelegate { 68 | 69 | /// 画面遷移開始時に呼ばれる。カスタムビューを使用して表示する。 70 | /// - Parameters: 71 | /// - presented: 呼び出し先ViewController 72 | /// - presenting: 呼び出し元ViewController 73 | /// - source: presentメソッドがプレゼンテーションプロセスを開始するために呼び出されたViewController 74 | /// - Returns: UIPresentationController 75 | public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 76 | return SemiModalPresentationController(presentedViewController: presented, 77 | presenting: presenting, 78 | overlayView: overlayView, 79 | indicator: indicator) 80 | } 81 | 82 | /// dismiss時に呼ばれる。dismissのアニメーション指定。 83 | /// - Parameter dismissed: dismissされるViewController 84 | /// - Returns: UIViewControllerAnimatedTransitioning 85 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 86 | return SemiModalDismissAnimatedTransition() 87 | } 88 | 89 | /// インタラクティブなdismissを制御する。 90 | /// - Parameter animator: animationController(forDismissed:)で指定したアニメーター 91 | /// - Returns: UIViewControllerInteractiveTransitioning 92 | public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 93 | guard dismissInteractiveTransition.isInteractiveDismalTransition else { return nil } 94 | return dismissInteractiveTransition 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5F5EA184257B469300AA714B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA183257B469300AA714B /* AppDelegate.swift */; }; 11 | 5F5EA186257B469300AA714B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA185257B469300AA714B /* SceneDelegate.swift */; }; 12 | 5F5EA188257B469300AA714B /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA187257B469300AA714B /* MainViewController.swift */; }; 13 | 5F5EA18B257B469300AA714B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F5EA189257B469300AA714B /* Main.storyboard */; }; 14 | 5F5EA18D257B469600AA714B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F5EA18C257B469600AA714B /* Assets.xcassets */; }; 15 | 5F5EA190257B469600AA714B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F5EA18E257B469600AA714B /* LaunchScreen.storyboard */; }; 16 | 5F5EA1A1257B471D00AA714B /* SemiModal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F5EA19F257B471D00AA714B /* SemiModal.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17 | 5F5EA1A4257B471D00AA714B /* SemiModal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F5EA19D257B471D00AA714B /* SemiModal.framework */; }; 18 | 5F5EA1A5257B471D00AA714B /* SemiModal.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5F5EA19D257B471D00AA714B /* SemiModal.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | 5F5EA1B2257B479900AA714B /* SemiModalOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1AB257B479900AA714B /* SemiModalOverlayView.swift */; }; 20 | 5F5EA1B3257B479900AA714B /* SemiModalDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1AC257B479900AA714B /* SemiModalDismissInteractiveTransition.swift */; }; 21 | 5F5EA1B4257B479900AA714B /* SemiModalIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1AD257B479900AA714B /* SemiModalIndicatorView.swift */; }; 22 | 5F5EA1B5257B479900AA714B /* SemiModalDismissAnimatedTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1AE257B479900AA714B /* SemiModalDismissAnimatedTransition.swift */; }; 23 | 5F5EA1B7257B479900AA714B /* SemiModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1B0257B479900AA714B /* SemiModalPresentationController.swift */; }; 24 | 5F5EA1B8257B479900AA714B /* SemiModalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1B1257B479900AA714B /* SemiModalPresenter.swift */; }; 25 | 5F5EA1BC257B482E00AA714B /* ModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F5EA1BB257B482E00AA714B /* ModalViewController.swift */; }; 26 | 5F5EA1C7257B4B8200AA714B /* ModalViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F5EA1C6257B4B8200AA714B /* ModalViewController.storyboard */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 5F5EA1A2257B471D00AA714B /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 5F5EA178257B469300AA714B /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 5F5EA19C257B471D00AA714B; 35 | remoteInfo = SemiModal; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXCopyFilesBuildPhase section */ 40 | 5F5EA1A9257B471D00AA714B /* Embed Frameworks */ = { 41 | isa = PBXCopyFilesBuildPhase; 42 | buildActionMask = 2147483647; 43 | dstPath = ""; 44 | dstSubfolderSpec = 10; 45 | files = ( 46 | 5F5EA1A5257B471D00AA714B /* SemiModal.framework in Embed Frameworks */, 47 | ); 48 | name = "Embed Frameworks"; 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXCopyFilesBuildPhase section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | 5F5EA180257B469300AA714B /* SemiModalSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SemiModalSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 5F5EA183257B469300AA714B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 56 | 5F5EA185257B469300AA714B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 57 | 5F5EA187257B469300AA714B /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 58 | 5F5EA18A257B469300AA714B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 59 | 5F5EA18C257B469600AA714B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 60 | 5F5EA18F257B469600AA714B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 61 | 5F5EA191257B469600AA714B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 5F5EA19D257B471D00AA714B /* SemiModal.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SemiModal.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 5F5EA19F257B471D00AA714B /* SemiModal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SemiModal.h; sourceTree = ""; }; 64 | 5F5EA1A0257B471D00AA714B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65 | 5F5EA1AB257B479900AA714B /* SemiModalOverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiModalOverlayView.swift; sourceTree = ""; }; 66 | 5F5EA1AC257B479900AA714B /* SemiModalDismissInteractiveTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiModalDismissInteractiveTransition.swift; sourceTree = ""; }; 67 | 5F5EA1AD257B479900AA714B /* SemiModalIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiModalIndicatorView.swift; sourceTree = ""; }; 68 | 5F5EA1AE257B479900AA714B /* SemiModalDismissAnimatedTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiModalDismissAnimatedTransition.swift; sourceTree = ""; }; 69 | 5F5EA1B0257B479900AA714B /* SemiModalPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiModalPresentationController.swift; sourceTree = ""; }; 70 | 5F5EA1B1257B479900AA714B /* SemiModalPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiModalPresenter.swift; sourceTree = ""; }; 71 | 5F5EA1BB257B482E00AA714B /* ModalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalViewController.swift; sourceTree = ""; }; 72 | 5F5EA1C6257B4B8200AA714B /* ModalViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ModalViewController.storyboard; sourceTree = ""; }; 73 | /* End PBXFileReference section */ 74 | 75 | /* Begin PBXFrameworksBuildPhase section */ 76 | 5F5EA17D257B469300AA714B /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | 5F5EA1A4257B471D00AA714B /* SemiModal.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 5F5EA19A257B471D00AA714B /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | 5F5EA177257B469300AA714B = { 95 | isa = PBXGroup; 96 | children = ( 97 | 5F5EA182257B469300AA714B /* SemiModalSample */, 98 | 5F5EA19E257B471D00AA714B /* SemiModal */, 99 | 5F5EA181257B469300AA714B /* Products */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 5F5EA181257B469300AA714B /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 5F5EA180257B469300AA714B /* SemiModalSample.app */, 107 | 5F5EA19D257B471D00AA714B /* SemiModal.framework */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 5F5EA182257B469300AA714B /* SemiModalSample */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 5F5EA1C4257B4A5C00AA714B /* Application */, 116 | 5F5EA1C0257B49FA00AA714B /* Presentation */, 117 | 5F5EA18C257B469600AA714B /* Assets.xcassets */, 118 | 5F5EA191257B469600AA714B /* Info.plist */, 119 | ); 120 | path = SemiModalSample; 121 | sourceTree = ""; 122 | }; 123 | 5F5EA19E257B471D00AA714B /* SemiModal */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 5F5EA19F257B471D00AA714B /* SemiModal.h */, 127 | 5F5EA1B1257B479900AA714B /* SemiModalPresenter.swift */, 128 | 5F5EA1B0257B479900AA714B /* SemiModalPresentationController.swift */, 129 | 5F5EA1AE257B479900AA714B /* SemiModalDismissAnimatedTransition.swift */, 130 | 5F5EA1AC257B479900AA714B /* SemiModalDismissInteractiveTransition.swift */, 131 | 5F5EA1AD257B479900AA714B /* SemiModalIndicatorView.swift */, 132 | 5F5EA1AB257B479900AA714B /* SemiModalOverlayView.swift */, 133 | 5F5EA1A0257B471D00AA714B /* Info.plist */, 134 | ); 135 | path = SemiModal; 136 | sourceTree = ""; 137 | }; 138 | 5F5EA1C0257B49FA00AA714B /* Presentation */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 5F5EA1C3257B4A4A00AA714B /* LaunchScreen */, 142 | 5F5EA1C1257B4A2500AA714B /* Main */, 143 | 5F5EA1C2257B4A3300AA714B /* Modal */, 144 | ); 145 | path = Presentation; 146 | sourceTree = ""; 147 | }; 148 | 5F5EA1C1257B4A2500AA714B /* Main */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 5F5EA187257B469300AA714B /* MainViewController.swift */, 152 | 5F5EA189257B469300AA714B /* Main.storyboard */, 153 | ); 154 | path = Main; 155 | sourceTree = ""; 156 | }; 157 | 5F5EA1C2257B4A3300AA714B /* Modal */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 5F5EA1BB257B482E00AA714B /* ModalViewController.swift */, 161 | 5F5EA1C6257B4B8200AA714B /* ModalViewController.storyboard */, 162 | ); 163 | path = Modal; 164 | sourceTree = ""; 165 | }; 166 | 5F5EA1C3257B4A4A00AA714B /* LaunchScreen */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 5F5EA18E257B469600AA714B /* LaunchScreen.storyboard */, 170 | ); 171 | path = LaunchScreen; 172 | sourceTree = ""; 173 | }; 174 | 5F5EA1C4257B4A5C00AA714B /* Application */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 5F5EA183257B469300AA714B /* AppDelegate.swift */, 178 | 5F5EA185257B469300AA714B /* SceneDelegate.swift */, 179 | ); 180 | path = Application; 181 | sourceTree = ""; 182 | }; 183 | /* End PBXGroup section */ 184 | 185 | /* Begin PBXHeadersBuildPhase section */ 186 | 5F5EA198257B471D00AA714B /* Headers */ = { 187 | isa = PBXHeadersBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 5F5EA1A1257B471D00AA714B /* SemiModal.h in Headers */, 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | /* End PBXHeadersBuildPhase section */ 195 | 196 | /* Begin PBXNativeTarget section */ 197 | 5F5EA17F257B469300AA714B /* SemiModalSample */ = { 198 | isa = PBXNativeTarget; 199 | buildConfigurationList = 5F5EA194257B469600AA714B /* Build configuration list for PBXNativeTarget "SemiModalSample" */; 200 | buildPhases = ( 201 | 5F5EA17C257B469300AA714B /* Sources */, 202 | 5F5EA17D257B469300AA714B /* Frameworks */, 203 | 5F5EA17E257B469300AA714B /* Resources */, 204 | 5F5EA1A9257B471D00AA714B /* Embed Frameworks */, 205 | ); 206 | buildRules = ( 207 | ); 208 | dependencies = ( 209 | 5F5EA1A3257B471D00AA714B /* PBXTargetDependency */, 210 | ); 211 | name = SemiModalSample; 212 | productName = SemiModalSample; 213 | productReference = 5F5EA180257B469300AA714B /* SemiModalSample.app */; 214 | productType = "com.apple.product-type.application"; 215 | }; 216 | 5F5EA19C257B471D00AA714B /* SemiModal */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = 5F5EA1A6257B471D00AA714B /* Build configuration list for PBXNativeTarget "SemiModal" */; 219 | buildPhases = ( 220 | 5F5EA198257B471D00AA714B /* Headers */, 221 | 5F5EA199257B471D00AA714B /* Sources */, 222 | 5F5EA19A257B471D00AA714B /* Frameworks */, 223 | 5F5EA19B257B471D00AA714B /* Resources */, 224 | ); 225 | buildRules = ( 226 | ); 227 | dependencies = ( 228 | ); 229 | name = SemiModal; 230 | productName = SemiModal; 231 | productReference = 5F5EA19D257B471D00AA714B /* SemiModal.framework */; 232 | productType = "com.apple.product-type.framework"; 233 | }; 234 | /* End PBXNativeTarget section */ 235 | 236 | /* Begin PBXProject section */ 237 | 5F5EA178257B469300AA714B /* Project object */ = { 238 | isa = PBXProject; 239 | attributes = { 240 | LastSwiftUpdateCheck = 1220; 241 | LastUpgradeCheck = 1220; 242 | TargetAttributes = { 243 | 5F5EA17F257B469300AA714B = { 244 | CreatedOnToolsVersion = 12.2; 245 | }; 246 | 5F5EA19C257B471D00AA714B = { 247 | CreatedOnToolsVersion = 12.2; 248 | LastSwiftMigration = 1220; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = 5F5EA17B257B469300AA714B /* Build configuration list for PBXProject "SemiModalSample" */; 253 | compatibilityVersion = "Xcode 9.3"; 254 | developmentRegion = en; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | en, 258 | Base, 259 | ); 260 | mainGroup = 5F5EA177257B469300AA714B; 261 | productRefGroup = 5F5EA181257B469300AA714B /* Products */; 262 | projectDirPath = ""; 263 | projectRoot = ""; 264 | targets = ( 265 | 5F5EA17F257B469300AA714B /* SemiModalSample */, 266 | 5F5EA19C257B471D00AA714B /* SemiModal */, 267 | ); 268 | }; 269 | /* End PBXProject section */ 270 | 271 | /* Begin PBXResourcesBuildPhase section */ 272 | 5F5EA17E257B469300AA714B /* Resources */ = { 273 | isa = PBXResourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 5F5EA190257B469600AA714B /* LaunchScreen.storyboard in Resources */, 277 | 5F5EA1C7257B4B8200AA714B /* ModalViewController.storyboard in Resources */, 278 | 5F5EA18D257B469600AA714B /* Assets.xcassets in Resources */, 279 | 5F5EA18B257B469300AA714B /* Main.storyboard in Resources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | 5F5EA19B257B471D00AA714B /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXResourcesBuildPhase section */ 291 | 292 | /* Begin PBXSourcesBuildPhase section */ 293 | 5F5EA17C257B469300AA714B /* Sources */ = { 294 | isa = PBXSourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 5F5EA1BC257B482E00AA714B /* ModalViewController.swift in Sources */, 298 | 5F5EA188257B469300AA714B /* MainViewController.swift in Sources */, 299 | 5F5EA184257B469300AA714B /* AppDelegate.swift in Sources */, 300 | 5F5EA186257B469300AA714B /* SceneDelegate.swift in Sources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | 5F5EA199257B471D00AA714B /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | 5F5EA1B5257B479900AA714B /* SemiModalDismissAnimatedTransition.swift in Sources */, 309 | 5F5EA1B3257B479900AA714B /* SemiModalDismissInteractiveTransition.swift in Sources */, 310 | 5F5EA1B8257B479900AA714B /* SemiModalPresenter.swift in Sources */, 311 | 5F5EA1B4257B479900AA714B /* SemiModalIndicatorView.swift in Sources */, 312 | 5F5EA1B2257B479900AA714B /* SemiModalOverlayView.swift in Sources */, 313 | 5F5EA1B7257B479900AA714B /* SemiModalPresentationController.swift in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | /* End PBXSourcesBuildPhase section */ 318 | 319 | /* Begin PBXTargetDependency section */ 320 | 5F5EA1A3257B471D00AA714B /* PBXTargetDependency */ = { 321 | isa = PBXTargetDependency; 322 | target = 5F5EA19C257B471D00AA714B /* SemiModal */; 323 | targetProxy = 5F5EA1A2257B471D00AA714B /* PBXContainerItemProxy */; 324 | }; 325 | /* End PBXTargetDependency section */ 326 | 327 | /* Begin PBXVariantGroup section */ 328 | 5F5EA189257B469300AA714B /* Main.storyboard */ = { 329 | isa = PBXVariantGroup; 330 | children = ( 331 | 5F5EA18A257B469300AA714B /* Base */, 332 | ); 333 | name = Main.storyboard; 334 | sourceTree = ""; 335 | }; 336 | 5F5EA18E257B469600AA714B /* LaunchScreen.storyboard */ = { 337 | isa = PBXVariantGroup; 338 | children = ( 339 | 5F5EA18F257B469600AA714B /* Base */, 340 | ); 341 | name = LaunchScreen.storyboard; 342 | sourceTree = ""; 343 | }; 344 | /* End PBXVariantGroup section */ 345 | 346 | /* Begin XCBuildConfiguration section */ 347 | 5F5EA192257B469600AA714B /* Debug */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | ALWAYS_SEARCH_USER_PATHS = NO; 351 | CLANG_ANALYZER_NONNULL = YES; 352 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_ENABLE_OBJC_WEAK = YES; 358 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 359 | CLANG_WARN_BOOL_CONVERSION = YES; 360 | CLANG_WARN_COMMA = YES; 361 | CLANG_WARN_CONSTANT_CONVERSION = YES; 362 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 363 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 364 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 365 | CLANG_WARN_EMPTY_BODY = YES; 366 | CLANG_WARN_ENUM_CONVERSION = YES; 367 | CLANG_WARN_INFINITE_RECURSION = YES; 368 | CLANG_WARN_INT_CONVERSION = YES; 369 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 370 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 371 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 373 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 374 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 375 | CLANG_WARN_STRICT_PROTOTYPES = YES; 376 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 377 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | COPY_PHASE_STRIP = NO; 381 | DEBUG_INFORMATION_FORMAT = dwarf; 382 | ENABLE_STRICT_OBJC_MSGSEND = YES; 383 | ENABLE_TESTABILITY = YES; 384 | GCC_C_LANGUAGE_STANDARD = gnu11; 385 | GCC_DYNAMIC_NO_PIC = NO; 386 | GCC_NO_COMMON_BLOCKS = YES; 387 | GCC_OPTIMIZATION_LEVEL = 0; 388 | GCC_PREPROCESSOR_DEFINITIONS = ( 389 | "DEBUG=1", 390 | "$(inherited)", 391 | ); 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 399 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 400 | MTL_FAST_MATH = YES; 401 | ONLY_ACTIVE_ARCH = YES; 402 | SDKROOT = iphoneos; 403 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 404 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 405 | }; 406 | name = Debug; 407 | }; 408 | 5F5EA193257B469600AA714B /* Release */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | ALWAYS_SEARCH_USER_PATHS = NO; 412 | CLANG_ANALYZER_NONNULL = YES; 413 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 414 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 415 | CLANG_CXX_LIBRARY = "libc++"; 416 | CLANG_ENABLE_MODULES = YES; 417 | CLANG_ENABLE_OBJC_ARC = YES; 418 | CLANG_ENABLE_OBJC_WEAK = YES; 419 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 420 | CLANG_WARN_BOOL_CONVERSION = YES; 421 | CLANG_WARN_COMMA = YES; 422 | CLANG_WARN_CONSTANT_CONVERSION = YES; 423 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 425 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 426 | CLANG_WARN_EMPTY_BODY = YES; 427 | CLANG_WARN_ENUM_CONVERSION = YES; 428 | CLANG_WARN_INFINITE_RECURSION = YES; 429 | CLANG_WARN_INT_CONVERSION = YES; 430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 432 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 433 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 434 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 435 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 436 | CLANG_WARN_STRICT_PROTOTYPES = YES; 437 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 438 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 439 | CLANG_WARN_UNREACHABLE_CODE = YES; 440 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 441 | COPY_PHASE_STRIP = NO; 442 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 443 | ENABLE_NS_ASSERTIONS = NO; 444 | ENABLE_STRICT_OBJC_MSGSEND = YES; 445 | GCC_C_LANGUAGE_STANDARD = gnu11; 446 | GCC_NO_COMMON_BLOCKS = YES; 447 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 448 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 449 | GCC_WARN_UNDECLARED_SELECTOR = YES; 450 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 451 | GCC_WARN_UNUSED_FUNCTION = YES; 452 | GCC_WARN_UNUSED_VARIABLE = YES; 453 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 454 | MTL_ENABLE_DEBUG_INFO = NO; 455 | MTL_FAST_MATH = YES; 456 | SDKROOT = iphoneos; 457 | SWIFT_COMPILATION_MODE = wholemodule; 458 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 459 | VALIDATE_PRODUCT = YES; 460 | }; 461 | name = Release; 462 | }; 463 | 5F5EA195257B469600AA714B /* Debug */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 467 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 468 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 469 | CODE_SIGN_STYLE = Automatic; 470 | INFOPLIST_FILE = SemiModalSample/Info.plist; 471 | LD_RUNPATH_SEARCH_PATHS = ( 472 | "$(inherited)", 473 | "@executable_path/Frameworks", 474 | ); 475 | PRODUCT_BUNDLE_IDENTIFIER = com.example.SemiModalSample; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | SWIFT_VERSION = 5.0; 478 | TARGETED_DEVICE_FAMILY = "1,2"; 479 | }; 480 | name = Debug; 481 | }; 482 | 5F5EA196257B469600AA714B /* Release */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 486 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 487 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 488 | CODE_SIGN_STYLE = Automatic; 489 | INFOPLIST_FILE = SemiModalSample/Info.plist; 490 | LD_RUNPATH_SEARCH_PATHS = ( 491 | "$(inherited)", 492 | "@executable_path/Frameworks", 493 | ); 494 | PRODUCT_BUNDLE_IDENTIFIER = com.example.SemiModalSample; 495 | PRODUCT_NAME = "$(TARGET_NAME)"; 496 | SWIFT_VERSION = 5.0; 497 | TARGETED_DEVICE_FAMILY = "1,2"; 498 | }; 499 | name = Release; 500 | }; 501 | 5F5EA1A7257B471D00AA714B /* Debug */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | CLANG_ENABLE_MODULES = YES; 505 | CODE_SIGN_STYLE = Automatic; 506 | CURRENT_PROJECT_VERSION = 1; 507 | DEFINES_MODULE = YES; 508 | DYLIB_COMPATIBILITY_VERSION = 1; 509 | DYLIB_CURRENT_VERSION = 1; 510 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 511 | INFOPLIST_FILE = SemiModal/Info.plist; 512 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 513 | LD_RUNPATH_SEARCH_PATHS = ( 514 | "$(inherited)", 515 | "@executable_path/Frameworks", 516 | "@loader_path/Frameworks", 517 | ); 518 | PRODUCT_BUNDLE_IDENTIFIER = com.example.SemiModal; 519 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 520 | SKIP_INSTALL = YES; 521 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 522 | SWIFT_VERSION = 5.0; 523 | TARGETED_DEVICE_FAMILY = "1,2"; 524 | VERSIONING_SYSTEM = "apple-generic"; 525 | VERSION_INFO_PREFIX = ""; 526 | }; 527 | name = Debug; 528 | }; 529 | 5F5EA1A8257B471D00AA714B /* Release */ = { 530 | isa = XCBuildConfiguration; 531 | buildSettings = { 532 | CLANG_ENABLE_MODULES = YES; 533 | CODE_SIGN_STYLE = Automatic; 534 | CURRENT_PROJECT_VERSION = 1; 535 | DEFINES_MODULE = YES; 536 | DYLIB_COMPATIBILITY_VERSION = 1; 537 | DYLIB_CURRENT_VERSION = 1; 538 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 539 | INFOPLIST_FILE = SemiModal/Info.plist; 540 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 541 | LD_RUNPATH_SEARCH_PATHS = ( 542 | "$(inherited)", 543 | "@executable_path/Frameworks", 544 | "@loader_path/Frameworks", 545 | ); 546 | PRODUCT_BUNDLE_IDENTIFIER = com.example.SemiModal; 547 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 548 | SKIP_INSTALL = YES; 549 | SWIFT_VERSION = 5.0; 550 | TARGETED_DEVICE_FAMILY = "1,2"; 551 | VERSIONING_SYSTEM = "apple-generic"; 552 | VERSION_INFO_PREFIX = ""; 553 | }; 554 | name = Release; 555 | }; 556 | /* End XCBuildConfiguration section */ 557 | 558 | /* Begin XCConfigurationList section */ 559 | 5F5EA17B257B469300AA714B /* Build configuration list for PBXProject "SemiModalSample" */ = { 560 | isa = XCConfigurationList; 561 | buildConfigurations = ( 562 | 5F5EA192257B469600AA714B /* Debug */, 563 | 5F5EA193257B469600AA714B /* Release */, 564 | ); 565 | defaultConfigurationIsVisible = 0; 566 | defaultConfigurationName = Release; 567 | }; 568 | 5F5EA194257B469600AA714B /* Build configuration list for PBXNativeTarget "SemiModalSample" */ = { 569 | isa = XCConfigurationList; 570 | buildConfigurations = ( 571 | 5F5EA195257B469600AA714B /* Debug */, 572 | 5F5EA196257B469600AA714B /* Release */, 573 | ); 574 | defaultConfigurationIsVisible = 0; 575 | defaultConfigurationName = Release; 576 | }; 577 | 5F5EA1A6257B471D00AA714B /* Build configuration list for PBXNativeTarget "SemiModal" */ = { 578 | isa = XCConfigurationList; 579 | buildConfigurations = ( 580 | 5F5EA1A7257B471D00AA714B /* Debug */, 581 | 5F5EA1A8257B471D00AA714B /* Release */, 582 | ); 583 | defaultConfigurationIsVisible = 0; 584 | defaultConfigurationName = Release; 585 | }; 586 | /* End XCConfigurationList section */ 587 | }; 588 | rootObject = 5F5EA178257B469300AA714B /* Project object */; 589 | } 590 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Application/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | @main 8 | class AppDelegate: UIResponder, UIApplicationDelegate { 9 | 10 | 11 | 12 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 13 | // Override point for customization after application launch. 14 | return true 15 | } 16 | 17 | // MARK: UISceneSession Lifecycle 18 | 19 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 20 | // Called when a new scene session is being created. 21 | // Use this method to select a configuration to create the new scene with. 22 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 23 | } 24 | 25 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 26 | // Called when the user discards a scene session. 27 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 28 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 29 | } 30 | 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Application/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 8 | 9 | var window: UIWindow? 10 | 11 | 12 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 13 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 14 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 15 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 16 | guard let _ = (scene as? UIWindowScene) else { return } 17 | } 18 | 19 | func sceneDidDisconnect(_ scene: UIScene) { 20 | // Called as the scene is being released by the system. 21 | // This occurs shortly after the scene enters the background, or when its session is discarded. 22 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 23 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 24 | } 25 | 26 | func sceneDidBecomeActive(_ scene: UIScene) { 27 | // Called when the scene has moved from an inactive state to an active state. 28 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 29 | } 30 | 31 | func sceneWillResignActive(_ scene: UIScene) { 32 | // Called when the scene will move from an active state to an inactive state. 33 | // This may occur due to temporary interruptions (ex. an incoming phone call). 34 | } 35 | 36 | func sceneWillEnterForeground(_ scene: UIScene) { 37 | // Called as the scene transitions from the background to the foreground. 38 | // Use this method to undo the changes made on entering the background. 39 | } 40 | 41 | func sceneDidEnterBackground(_ scene: UIScene) { 42 | // Called as the scene transitions from the foreground to the background. 43 | // Use this method to save data, release shared resources, and store enough scene-specific state information 44 | // to restore the scene back to its current state. 45 | } 46 | 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Presentation/LaunchScreen/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Presentation/Main/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Presentation/Main/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | import SemiModal 7 | 8 | class MainViewController: UIViewController { 9 | 10 | private var semiModalPresenter = SemiModalPresenter() 11 | 12 | @IBAction func openModalButtonDidTap(_ sender: Any) { 13 | let viewController = ModalViewController.instantiateInitialViewControllerFromStoryboard() 14 | semiModalPresenter.viewController = viewController 15 | present(viewController, animated: true) 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Presentation/Modal/ModalViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /SemiModalSample/SemiModalSample/Presentation/Modal/ModalViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2020 Rakuten, Inc. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | import SemiModal 7 | 8 | final class ModalViewController: UIViewController { 9 | 10 | @IBOutlet private weak var contentView: UIView! 11 | } 12 | 13 | extension ModalViewController { 14 | 15 | static func instantiateInitialViewControllerFromStoryboard() -> Self { 16 | return UIStoryboard(name: String(describing: self), bundle: Bundle(for: self)) 17 | .instantiateInitialViewController() as! Self 18 | } 19 | } 20 | 21 | extension ModalViewController: SemiModalPresenterDelegate { 22 | 23 | var semiModalContentHeight: CGFloat { 24 | return contentView.frame.height 25 | } 26 | } 27 | --------------------------------------------------------------------------------