Giter Site home page Giter Site logo

applidium / overlaycontainer Goto Github PK

View Code? Open in Web Editor NEW
1.1K 15.0 94.0 18.72 MB

Non-intrusive iOS UI library to implement overlay based interfaces

Home Page: https://gaetanzanella.github.io/2018-12-17/replicating-apple-maps-overlay

License: Other

Swift 98.56% Ruby 1.44%
overlay ios uikit bottomsheet panel floating

overlaycontainer's Introduction

OverlayContainer is a UI library written in Swift. It makes easier to develop overlay based interfaces, such as the one presented in the Apple Maps, Stocks or Shortcuts apps

Platform Swift4 Swift5 CocoaPods Carthage Build Status License


⚠️ In iOS 15, consider using UISheetPresentationController before OverlayContainer


OverlayContainer tries to be as lightweight and non-intrusive as possible. The layout and the UI customization are done by you to avoid to corrupt your project.

It perfectly mimics the overlay presented in the Siri Shotcuts app. See this article for details.

  • Unlimited notches
  • Notches modifiable at runtime
  • Adaptive to any custom layouts
  • Rubber band effect
  • Animations and target notch policy fully customizable
  • Unit tested

See the provided examples for help or feel free to ask directly.



Usage

Setup

The main component of the library is the OverlayContainerViewController. It defines an area where a view controller, called the overlay view controller, can be dragged up and down, hiding or revealing the content underneath it.

OverlayContainer uses the last view controller of its viewControllers as the overlay view controller. It stacks the other view controllers on top of each other, if any, and adds them underneath the overlay view controller.

A startup sequence might look like this:

let mapsController = MapsViewController()
let searchController = SearchViewController()

let containerController = OverlayContainerViewController()
containerController.delegate = self
containerController.viewControllers = [
    mapsController,
    searchController
]

window?.rootViewController = containerController

Specifing only one view controller is absolutely valid. For instance, in MapsLikeViewController the overlay only covers partially its content.

The overlay container view controller needs at least one notch. Implement OverlayContainerViewControllerDelegate to specify the number of notches wished:

enum OverlayNotch: Int, CaseIterable {
    case minimum, medium, maximum
}

func numberOfNotches(in containerViewController: OverlayContainerViewController) -> Int {
    return OverlayNotch.allCases.count
}

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    heightForNotchAt index: Int,
                                    availableSpace: CGFloat) -> CGFloat {
    switch OverlayNotch.allCases[index] {
        case .maximum:
            return availableSpace * 3 / 4
        case .medium:
            return availableSpace / 2
        case .minimum:
            return availableSpace * 1 / 4
    }
}

Overlay style

The overlay style defines how the overlay view controller will be constrained in the OverlayContainerViewController.

enum OverlayStyle {
    case flexibleHeight
    case rigid
    case expandableHeight // default
}

let overlayContainer = OverlayContainerViewController(style: .rigid)
  • rigid

rigid

The overlay view controller will be constrained with a height equal to the highest notch. The overlay won't be fully visible until the user drags it up to this notch.

  • flexibleHeight

flexible

The overlay view controller will not be height-constrained. It will grow and shrink as the user drags it up and down.

Note though that while the user is dragging the overlay, the overlay's view may perform some extra layout computations. This is specially true for the table views or the collection views : some cells may be dequeued or removed when its frame changes. Try .rigid if you encounter performance issues.

Be careful to always provide a minimum height higher than the intrinsic content of your overlay.

  • expandableHeight

expandable

The overlay view controller will be constrained with a height greater or equal to the highest notch. Its height will be expanded if the overlay goes beyond the highest notch (it could happen if the translation function or the animation controller allow it).

Scroll view support

The container view controller can coordinate the scrolling of a scroll view with the overlay translation.

scrollToTranslation

Use the dedicated delegate method:

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    scrollViewDrivingOverlay overlayViewController: UIViewController) -> UIScrollView? {
    return (overlayViewController as? DetailViewController)?.tableView
}

Or directly set the dedicated property:

let containerController = OverlayContainerViewController()
containerController.drivingScrollView = myScrollView

Make sure to set UIScrollView.alwaysBounceVertical to true so the scroll view will always scroll regardless of its content size.

Pan gesture support

The container view controller detects pan gestures on its own view. Use the dedicated delegate method to check that the specified starting pan gesture location corresponds to a grabbable view in your custom overlay.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    shouldStartDraggingOverlay overlayViewController: UIViewController,
                                    at point: CGPoint,
                                    in coordinateSpace: UICoordinateSpace) -> Bool {
    guard let header = (overlayViewController as? DetailViewController)?.header else {
        return false
    }
    let convertedPoint = coordinateSpace.convert(point, to: header)
    return header.bounds.contains(convertedPoint)
}

Tracking the overlay

You can track the overlay motions using the dedicated delegate methods:

  • Translation Start

Tells the delegate when the user is about to start dragging the overlay view controller.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    willStartDraggingOverlay overlayViewController: UIViewController)
  • Translation End

Tells the delegate when the user finishs dragging the overlay view controller with the specified velocity.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    willEndDraggingOverlay overlayViewController: UIViewController,
                                    atVelocity velocity: CGPoint)
  • Translation In Progress

Tells the delegate when the container is about to move the overlay view controller to the specified notch.

In some cases, the overlay view controller may not successfully reach the specified notch. If the user cancels the translation for instance. Use overlayContainerViewController(_:didMove:toNotchAt:) if you need to be notified each time the translation succeeds.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    willMoveOverlay overlayViewController: UIViewController,
                                    toNotchAt index: Int)

Tells the delegate when the container has moved the overlay view controller to the specified notch.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    didMoveOverlay overlayViewController: UIViewController,
                                    toNotchAt index: Int)

Tells the delegate whenever the overlay view controller is about to be translated.

The delegate typically implements this method to coordinate changes alongside the overlay view controller's translation.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    willTranslateOverlay overlayViewController: UIViewController,
                                    transitionCoordinator: OverlayContainerTransitionCoordinator)

The transition coordinator provides information about the translation that is about to start:

/// A Boolean value that indicates whether the user is current dragging the overlay.
var isDragging: Bool { get }

/// The overlay velocity.
var velocity: CGPoint { get }

/// The current translation height.
var overlayTranslationHeight: CGFloat { get }

/// The notch indexes.
var notchIndexes: Range<Int> { get }

/// The reachable indexes. Some indexes might be disabled by the `canReachNotchAt` delegate method.
var reachableIndexes: [Int] { get }

/// Returns the height of the specified notch.
func height(forNotchAt index: Int) -> CGFloat

/// A Boolean value indicating whether the transition is explicitly animated.
var isAnimated: Bool { get }

/// A Boolean value indicating whether the transition was cancelled.
var isCancelled: Bool { get }

/// The overlay height the container expects to reach.
var targetTranslationHeight: CGFloat { get }

and allows you to add animations alongside it:

transitionCoordinator.animate(alongsideTransition: { context in
    // ...
}, completion: nil)

Examples

To test the examples, open OverlayContainer.xcworkspace and run the OverlayContainer_Example target.

Choose the layout you wish to display in the AppDelegate:

  • MapsLikeViewController: A custom layout which adapts its hierachy on rotations.

Maps

  • ShortcutsLikeViewController: A custom layout which adapts its hierachy on trait collection changes: Moving from a UISplitViewController on regular environment to a simple StackViewController on compact environment. Visualize it on an iPad Pro.

Shortcuts

Advanced usage

Multiple overlays

OverlayContainer does not provide a built-in view controller navigation management. It focuses its effort on the overlay translation.

However in the project, there is an example of a basic solution to overlay multiple overlays on top of each other, like in the Apple Maps app. It is based on an UINavigationController and a custom implementation of its delegate:

// MARK: - UINavigationControllerDelegate

func navigationController(_ navigationController: UINavigationController,
                          animationControllerFor operation: UINavigationController.Operation,
                          from fromVC: UIViewController,
                          to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return OverlayNavigationAnimationController(operation: operation)
}

func navigationController(_ navigationController: UINavigationController,
                          didShow viewController: UIViewController,
                          animated: Bool) {
    overlayController.drivingScrollView = (viewController as? SearchViewController)?.tableView
}

OverlayNavigationAnimationController tweaks the native behavior of the UINavigationController: it slides the pushed view controllers up from the bottom of the screen. Feel free to add shadows and modify the animation curve depending on your needs. The only restriction is that you can not push an UINavigationController inside another UINavigationController.

Presenting an overlay container

The translation of an overlay view controller can be coupled with the presentation state of its container. Subclass OverlayContainerPresentationController to be notified any time an overlay translation occurs in the presented content or use the built-in OverlayContainerSheetPresentationController class.

A frequent use case is to reproduce the presentation style of an UIActivityViewController. ActivityControllerPresentationLikeViewController provides a basic implementation of it:

func displayActivityLikeViewController() {
    let container = OverlayContainerViewController()
    container.viewControllers = [MyActivityViewController()]
    container.transitioningDelegate = self
    container.modalPresentationStyle = .custom
    present(container, animated: true, completion: nil)
}

// MARK: - UIViewControllerTransitioningDelegate

func presentationController(forPresented presented: UIViewController,
                            presenting: UIViewController?,
                            source: UIViewController) -> UIPresentationController? {
    return OverlayContainerSheetPresentationController(
        presentedViewController: presented,
        presenting: presenting
    )
}

If the user taps the background content or drags the overlay down fastly, the container controller will be automatically dismissed.

Enabling & disabling notches

OverlayContainer provides a easy way to enable & disable notches on the fly. A frequent use case is to show & hide the overlay. ShowOverlayExampleViewController provides a basic implementation of it:

var showsOverlay = false

func showOrHideOverlay() {
    showsOverlay.toggle()
    let targetNotch: Notch = showsOverlay ? .med : .hidden
    overlayContainerController.moveOverlay(toNotchAt: targetNotch.rawValue, animated: true)
}

// MARK: - OverlayContainerViewControllerDelegate

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    heightForNotchAt index: Int,
                                    availableSpace: CGFloat) -> CGFloat {
    switch Notch.allCases[index] {
    case .max:
        return ...
    case .med:
        return ...
    case .hidden:
        return 0
    }
}

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    canReachNotchAt index: Int,
                                    forOverlay overlayViewController: UIViewController) -> Bool {
    switch Notch.allCases[index] {
    case .max:
        return showsOverlay
    case .med:
        return showsOverlay
    case .hidden:
        return !showsOverlay
    }
}

Make sure to use the rigid overlay style if the content can not be flattened.

Backdrop view

Coordinate the overlay movements to the aspect of a view using the dedicated delegate methods. See the backdrop view example.

backdrop

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    willTranslateOverlay overlayViewController: UIViewController,
                                    transitionCoordinator: OverlayContainerTransitionCoordinator) {
    transitionCoordinator.animate(alongsideTransition: { [weak self] context in
        self?.backdropViewController.view.alpha = context.translationProgress()
    }, completion: nil)
}

Safe Area issues

Be careful when using safe areas. As described in the WWDC "UIKit: Apps for Every Size and Shape" video, the safe area insets will not be updated if your views exceeds the screen bounds. This is specially the case when using the OverlayStyle.expandableHeight: when the overlay exceeds the bottom screen limit, its safe area will not be updated.

The simpliest way to handle the safe area correctly is to compute your notch heights using the safeAreaInsets of the container and avoid the safeAreaLayoutGuide use in your overlay view:

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    heightForNotchAt index: Int,
                                    availableSpace: CGFloat) -> CGFloat {
    let bottomInset = containerViewController.view.safeAreaInsets.bottom
    switch OverlayNotch.allCases[index] {

        // ...

        case .minimum:
            return bottomInset + 100
    }
}

If you depend on UIKit native components that do not ignore the safe area like a UINavigationBar, use the OverlayStyle.flexibleHeight style.

Custom Translation

Adopt OverlayTranslationFunction to modify the relation between the user's finger translation and the actual overlay translation.

By default, the overlay container uses a RubberBandOverlayTranslationFunction that provides a rubber band effect.

rubberBand

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                    overlayTranslationFunctionForOverlay overlayViewController: UIViewController) -> OverlayTranslationFunction? {
    let function = RubberBandOverlayTranslationFunction()
    function.factor = 0.7
    function.bouncesAtMinimumHeight = false
    return function
}

Custom Translation Animations

Adopt OverlayTranslationTargetNotchPolicy & OverlayAnimatedTransitioning protocols to define where the overlay should go once the user's touch is released and how to animate the translation.

By default, the overlay container uses a SpringOverlayTranslationAnimationController that mimics the behavior of a spring. The associated target notch policy RushingForwardTargetNotchPolicy will always try to go forward if the user's finger reachs a certain velocity. It might also decide to skip some notches if the user goes too fast.

Tweak the provided implementations or implement our own objects to modify the overlay translation behavior.

animations

func overlayTargetNotchPolicy(for overlayViewController: UIViewController) -> OverlayTranslationTargetNotchPolicy? {
    let policy = RushingForwardTargetNotchPolicy()
    policy.minimumVelocity = 0
    return policy
}

func animationController(for overlayViewController: UIViewController) -> OverlayAnimatedTransitioning? {
    let controller = SpringOverlayTranslationAnimationController()
    controller.damping = 0.2
    return controller
}

Reloading the notches

You can reload all the data that is used to construct the notches using the dedicated method:

func invalidateNotchHeights()

This method does not reload the notch heights immediately. It only clears the current container's state. Because the number of notches may change, the container will use its target notch policy to determine where to go. Call moveOverlay(toNotchAt:animated:) to override this behavior.

Requirements

OverlayContainer is written in Swift 5. Compatible with iOS 10.0+.

Installation

OverlayContainer is available through CocoaPods. To install it, simply add the following line to your Podfile:

Cocoapods

pod 'OverlayContainer'

Carthage

Add the following to your Cartfile:

github "https://github.com/applidium/OverlayContainer"

Swift Package Manager

OverlayContainer can be installed as a Swift Package with Xcode 11 or higher. To install it, add a package using Xcode or a dependency to your Package.swift file:

.package(url: "https://github.com/applidium/OverlayContainer.git", from: "3.4.0")

SwiftUI

See DynamicOverlay

Author

@gaetanzanella, [email protected]

License

OverlayContainer is available under the MIT license. See the LICENSE file for more info.

overlaycontainer's People

Contributors

denispoifol avatar gaetanzanella avatar kocmohabta avatar peterkovacs avatar sendtobo avatar ydnar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

overlaycontainer's Issues

Fix Unit tests

Since the Carthage support, unit tests fail because of the Quick & Nimble dependancies. It should be fixed.

Search Field not enable

The search field is not enable!
Unable to enter any text inside searchBar.

One more In cocoacontrols its says objective-C but the project build in swift.

Multiple Overlay with different notches?

Hi,

is it possible to add multiple overlays which are nested? So I've got a background layer, a first overlay layer, and a second overlay with the special condition that the second overlay has not the full height of the first overlay layer and its max height is limited to 2/3 of the height of the first overlay.

I've created an image to illustrate it.

description_notches

Thank you.

Duration of animation for moveOverlay

This is more of a request for help than an issue, I guess, but I can't figure out how to set the duration of the animation when calling moveOverlay(toNotchAt:,animated:). I even considered importing the entire OverlayContainer as classes instead of a pod so I could manipulate it if it was private, but I can't find a duration anywhere, just velocity and advanced animation protocols.
It would be nice to make it animate alongside another animation too, but I just don't understand how.
The ShowOverlayExample just uses the basic "moveOverlay" with the default duration, so it couldn't help me..

Subclass OverlayContainerViewController?

Currently it is not possible to subclass OverlayContainerViewController, afaik.
Xcode error message: "Cannot inherit from non-open class 'OverlayContainerViewController' outside of its defining module"
This is probably due to OverlayContainerViewController being "public" and not "open". Open exists since Swift 3 and allows a class or function to be subclassed or overridden outside the current module.
It would be great if we could subclass OverlayContainerViewController for custom contained overlays.

didEndDraggingOverlay is called after a moveOverlay call

This is not a bug and intentional I'd guess, but what do you think about separating 'dragging' and calling moveOverlay callbacks, e.g something similar to

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                        didEndDraggingOverlay overlayViewController: UIViewController,
                                        transitionCoordinator: OverlayContainerTransitionCoordinator) {}

The above would be the original callback but only called when a user actually drags.

func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                        didEndMovingOverlay overlayViewController: UIViewController,
                                        transitionCoordinator: OverlayContainerTransitionCoordinator) {}

The above would be an additional callback but only called after moveOverlay call has finished?

Thoughts?

First tap in UITableView after dragging up or down is ignored

I have found an issue where if your overlay view controller contains a table view and drives the swipe up/down, after the up/down animation is complete (after overlayContainerViewController(containerViewController: _, willTranslateOverlay: _, transitionCoordinator: _)) the first tap on the table view doesn't register. You need to tap again. You can also see that the scroll indicator stays visible and doesn't disappear as it should. You can see this behaviour in your example project with BackdropExampleViewController.

navigation preferLargeTitles breaks layout constraints

Hello there,

For starters, this project is great and I have been enjoying using it. I am running into an issue because I'm using a navigation controller with large titles. This creates a constraint error:

[LayoutConstraints] Unable to simultaneously satisfy constraints.
	Probably at least one of the constraints in the following list is one you don't want. 
	Try this: 
		(1) look at each constraint and try to figure out which you don't expect; 
		(2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x600002d929e0 OverlayContainer_Example.DetailHeaderView:0x7f8bbb509520.height == 70   (active)>",
    "<NSLayoutConstraint:0x600002d92c10 OverlayContainer_Example.DetailHeaderView:0x7f8bbb509520.top == UILayoutGuide:0x6000037a0700'UIViewSafeAreaLayoutGuide'.top   (active)>",
    "<NSLayoutConstraint:0x600002d92df0 UITableView:0x7f8bbb827600.bottom == UIView:0x7f8bbb4112f0.bottom   (active)>",
    "<NSLayoutConstraint:0x600002d92ee0 V:[OverlayContainer_Example.DetailHeaderView:0x7f8bbb509520]-(0)-[UITableView:0x7f8bbb827600]   (active)>",
    "<NSLayoutConstraint:0x600002d92c60 V:|-(0)-[UIView:0x7f8bbb4112f0]   (active, names: '|':OverlayContainer.OverlayContainerView:0x7f8bbb401fb0 )>",
    "<NSLayoutConstraint:0x600002d91ae0 UIView:0x7f8bbb4112f0.bottom == OverlayContainer.OverlayContainerView:0x7f8bbb401fb0.bottom   (active)>",
    "<NSLayoutConstraint:0x600002d99400 V:|-(0)-[OverlayContainer.OverlayContainerView:0x7f8bbb401fb0]   (active, names: '|':OverlayContainer.OverlayTranslationView:0x7f8bbb407c10 )>",
    "<NSLayoutConstraint:0x600002d992c0 OverlayContainer.OverlayTranslationView:0x7f8bbb407c10.height == 203   (active)>",
    "<NSLayoutConstraint:0x600002d99310 OverlayContainer.OverlayContainerView:0x7f8bbb401fb0.bottom == OverlayContainer.OverlayTranslationView:0x7f8bbb407c10.bottom   (active)>",
    "<NSLayoutConstraint:0x600002d92ad0 'UIViewSafeAreaLayoutGuide-top' V:|-(140)-[UILayoutGuide:0x6000037a0700'UIViewSafeAreaLayoutGuide']   (active, names: '|':UIView:0x7f8bbb4112f0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600002d929e0 OverlayContainer_Example.DetailHeaderView:0x7f8bbb509520.height == 70   (active)>

This can be replicated on the example repo by setting the target to ios11, and then adding this code to AppDelegate to setup a basic navigation controller.

let navigationController = UINavigationController(rootViewController: ShortcutsLikeViewController())
navigationController.navigationBar.prefersLargeTitles = true
window?.rootViewController = navigationController

Not sure if theres something else I can do to get around this, or whether its just a bug in OverlayContainer.

Thanks in advance for the help!

Example project fails to build

I'm seeing two errors in the example project when I try building it.
Repro:

  1. Download project via https
  2. Navigate to example project directory in terminal
  3. pod install
  4. Open xcworkspace
  5. Cmd+R

Expected: Project builds and runs.

Actual: Two errors prevent building

:-1: /Users/aaron/Downloads/ADOverlayContainer-master/Example/Pods/Pods/Target Support Files/Pods-OverlayContainer_Example/Pods-OverlayContainer_Example.debug.xcconfig: unable to open file (in target "OverlayContainer_Example" in project "OverlayContainer") (in target 'OverlayContainer_Example')

:-1: /Users/aaron/Downloads/ADOverlayContainer-master/Example/Pods/Pods/Target Support Files/Pods-OverlayContainer_Tests/Pods-OverlayContainer_Tests.debug.xcconfig: unable to open file (in target "OverlayContainer_Tests" in project "OverlayContainer") (in target 'OverlayContainer_Tests')

Overlay container on all other ViewController

I want to overlays the OverlayContainer even the top view controller was changed ( ex: push
or pop a new view controller from origin view controller which has created OverlayContainer)

btw, I can implement the function just manually pass the OverlayContainer view controller to destination view controller and if destination view controller has the OverlayContainer and just add to self view, it is easy, but sometimes hard to implement the function with nested view controller and delegate not assigned itself,

I just searched few things and I could got a keyword Window, but didn't thinking know how to implement,

is anyone implement the flow ??, give me ideas, thank you

scrollViewDrivingOverlay for multiple child views

I have controller with multiple controllers. And I have scrollView in every child controller.

I need to call

    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
                                        scrollViewDrivingOverlay overlayViewController: UIViewController) -> UIScrollView?

func every time I change visible child view.
How can I solve it?

Current Notch Position

If we can check current position or get notified when position changes, that would be great.

Thanks

`willTranslateOverlay:` isn't being called after the user stops dragging

I'm trying to fade away views when the user drags the overlay or when the overlay is travelling between notches, but willTranslateOverlay: doesn't appear to be called on the delegate when the user has let go of the overlay and the overlay starts travelling automatically to the nearest notch.

Carthage build not compatible with XCode 10.2 / Swift 5

With XCode 10.2 and Swift 5, building ADOverlayContainer fails because the Nimble dependency is not compatible with the new Swift toolchain.

Currently ADOverlayContainer is referencing:

github "Quick/Nimble" ~> 7.3
github "Quick/Quick" ~> 1.3

But these Nimble versions still use the Swift 3 toolchain which is no longer supported in the XCode 10.2 build tools.

This can be solved by updating the Nimble dependencies to the latest versions:

github "Quick/Nimble" ~> 8.0
github "Quick/Quick" ~> 2.0

It would be great, if you could update that. (I know, I could have made a pull request for that but I found that overkill — and also I don't know about your test setup and if you can simple upgrade Nimble or if there are breaking changes in version 8)

Thanks for your great work on this framework! 💜

Animation jumps when touching overlay during animation (BackdropExampleViewController)

Hi,
I'm trying to animate other views in sync with the overlay transition. The BackdropExampleViewController example comes very close to what I want to do.

Everything works fine, but when I slide up the overlay, and then quickly slide it down again (before the slide-up animation has completed), the background transparency "jumps" a bit.

I've attached a video. It looks subtle here, but it becomes more annoying in my actual application. Do you have an idea how to fix this?

Best,
Johannes
animation.mov.zip

Rigid issue

"let overlayContainer = OverlayContainerViewController(style: .rigid)" - This feature is not working for me.

Support for top to bottom overlay

Would it be possible to support drag down overlay view with this library. I managed to achieve the desired effect by flipping the transform however as expected the pan gesture would need to be adjusted too

Do you have plans to support this?

MapsLikeViewController using SnapKit

Hello,

First off thank you so much for this awesome library. It looks great! 😃

I've been trying to replicate the MapsLikeViewController.swift page using SnapKit instead of storyboards. I got close however touches of map don't go through since the overlay container captures them, despite using the Passthrough view.

I've created a small sample repo here. Any help would be appreciated.

Thanks,
-Sami

3.0.0 release

3.0.0 will provide:

  • A new style expandableHeight
  • A fix when multiple OverlayContainer track the same scroll
  • A better state invalidation management
  • A new translation animation controller without spring behavior
  • New delegate API fully tested

addChild not recognized

Hi,
I just upgraded from 1.1.2 to 1.3.0 and the extension
func addChild(_ child: UIViewController, in containerView: UIView)
was not recognized by my app, suggesting me to use UIKit's addChild(). I checked the code differences and the only difference I could find was the that in 1.1.2 the methods are marked as public. Even tough XCode says public is redundant.
I cleaned the app and still had to revert to 1.1.2

I like your library! nice work!

Drawer not responding to scroll in contained scrollView when in navigationController?

I've stumbled on an issue where the drawer won't accept scrolling at all. I first discovered this because I'm trying to make this work with a CollectionView instead of a TableView, but I manage to reproduce it with tableView as well.

Reproduce:
Open the OverlayContainer_Example-project
• AppDelegate:18, change to window?.rootViewController = ModalNavigationViewController()
• SearchViewController:44, insert self.tableView.bounces = false
Observe the following:

This seems to be due to bounces=false, since it doesn't happen without it. But this is happening to me by default with UICollectionView, even though bounces = true.

Also, if you now change the SearchController:58 return 10 instead of 100, then it's actually impossible to minimize it by dragging the content, because you can't scroll up or down, due to no bouncing:

Not shown in the gif; it's still possible to move it by dragging on the searchbar-area.

So, the tableView.bounces=false makes this particular problem - but my issue is that this happens by default when I use a collectionView, and I'm not sure how to fix it.
I did use the delegate to set the overlayController.drivingScrollView as in the example, which makes it scrollable. And everything is working perfectly as long as the height of the content is taller than the max notch, so scrolling can occur everywhere. But when the content size is somewhere between minimum and maximum notch, then it acts weird when dragging to max height, and won't be dragged up/down after that.

Edit; I see now that the scrollViewDidScroll doesn't fire when the content is maximized.. not sure how to investigate further.

When DrivingScrollView has bounces=false, the overlay does not respond

When using a normal overlay without a drivingScrollView, and you try to drag it too far up, it has this nice dampening effect on the entire overlay (it lets you drag it a few pixels, then bounces back). I wanted to replicate this with a tableView as content, but when dragging it too far top, the overlay stays the same (max notch) and the tableView scrolls out of bounds and bounces back. I thought maybe it would work if I disabled bounces, but that just makes the entire overlay unscrollable, probably because didScroll isn't called.
Is there any other way of replicating the dampening, but with scrollViews?

Trigger Translation to certain Notch from code?

Hi, thanks for creating this library.

I have a usecase where I would like to display the Overlay at a later point and not immediately in a StackedViewController as in the examples. Few options that might help me in this are:

  1. Trigger the translations to each Notch position from code?
  2. present the OverlayContainerView from code?
  3. Use an own UIViewControllerTransitioningDelegate?

Do any of them make sense if so are there some examples (might have overlooked something and I'm rather new to iOS and Swift).

Wrong container Inset

I added a UINavigationController to the BackdropExampleViewController:

overlayController.viewControllers = [UINavigationController(rootViewController: searchViewController)]

Now there is space on top of the navigation bar when I let the swipe to the maximum state. When I drag it there it is fixed.
IMG_A0B96DA1203E-1

I already tried setting automaticallyAdjustsScrollViewInsets = false on the navigation controller.
Could someone please help me fixing this?

Unable to subclass OverlayContainerViewController. Everything is public, not open

This is more a question than an issue, sorry if it's not the right place, but I am experimenting with the container and found the need to retain some additional information/data within the container. I would like to subclass the OverlayContainerViewController (e.g class MyCustomContainerViewController:OverlayContainerViewController) and add my data there, as well as it would give me the opportunity to directly override other functions if needed (if the functions are changed to open as well).

Is there a reason this project is public rather than open?

I could just include the source files into my project to fix it (same module), but with your recent addition of Swift Package, I'd like to do it the right way.

Wrong spring animation on overlays containing subviews pinned to bottom

The default overlay animator SpringOverlayTranslationAnimationController doesn't animate correctly overlays with subviews pinned to bottom.

bug

The bug seems to be related to UISpringTimingParameters which animates all the components of the frame of each views if the initialVelocity parameter is not null. Even if the views are pinned to the bottom (see how the red view goes beyond its bottom limit when animated).

spring

Page sheet dismiss gesture conflict with driving scroll view

When scrolling down any scroll view in the overlay in view controllers presented using page sheet modal presentation style, the view controller is interactively dismissed.

Page sheet should not be dismissed when scrolling the driving scroll view down. But it could be enabled for other other areas outside the overlay controller.

OverlayViewController is not layout before animation when set before moveOverlay(toNotchAt:animated:)

When setting the viewControllers property just before animating appearance of the overlay :

overlayContainerViewController.viewControllers = [
    mainViewController,
    backdropViewController,
    overlayViewController,
].compactMap { $0 }
overlayContainerViewController.moveOverlay(to: .medium, animated: true)

We end up with the overlayViewcontroller being animated in its height like it should, but also in its width because its view did not layout properly before the begining of the animation.

I could make this work by forcing the layout of the superview of the overlayViewController, but it is a hacky solution, and it would definitely be better if the pod handled this force layout on its own :

overlayContainerViewController.viewControllers = [
    mainViewController,
    backdropViewController,
    overlayViewController,
].compactMap { $0 }
overlayViewController?.view.superview?.setNeedsLayout()
overlayViewController?.view.superview?.layoutIfNeeded()
overlayContainerViewController.moveOverlay(to: .medium, animated: true)

Dismissable by swipe

Is it possible to dismiss the overlay by swiping down with a certain velocity?

I was thinking that it might be possible to hook into the process before/while the notch policy would kick-in or even do this with a notch policy, but somehow that seems kludgy and I am not sure this is the way to go. Any pointers are welcome.

Latest stable Cocoapods version 1.6.1 fails to parse swift_versions option

If a Podfile specifies ADOverlayContainer dependency by commit like so:
pod 'OverlayContainer', :git => 'https://github.com/applidium/ADOverlayContainer.git', :commit => '570dc63ca719db8f98bf46ea726d228a3204ed3d'

Then command pod install fails:

[!] Failed to load 'OverlayContainer' podspec:
[!] Invalid `OverlayContainer.podspec` file: undefined method `swift_versions=' for #<Pod::Specification name="OverlayContainer">
Did you mean?  swift_version=
               swift_version.

 #  from /var/folders/8g/86qwfhy13c9cgkyw0pw04k5c0000gn/T/d20190502-74201-1hkatng/OverlayContainer.podspec:15
 #  -------------------------------------------
 #    s.swift_version    = '4.2'
 >    s.swift_versions = ['4.2']
 #
 #  -------------------------------------------

And this issue on CocoaPods github page tells that swift_versions option will only be available when 1.7.0 is released: CocoaPods/CocoaPods#8191

That is a problem for people who would like to make a fork and specify an exact commit
Is this option even necessary now?

P.S: Thanks for this beautiful framework!

Bottom of Rigid layout panel moves above bottom of screen when dragging, is there a way to stop this?

Hello, really liking the library so far as it feels more responsive than other libraries and feels like apple’s own floating panel.

I just have a quick question about the ridged style. Is there a way to stop the bottom of the overlay container from moving higher than the bottom of the screen as the user drags. I’ve tried using the flexible style for my layout but the overlay controller squishes my stack view.

Pretty much just wanting to know if there’s a way to pin the bottom of the rigid overlay controller to the bottom of the screen.

`reloadNotchHeights()` should be exposed

I have a situation where my notch heights are changing, so I found the function OverlayContainerViewControllerConfiguration.reloadNotchHeights() which does the job.
Unfortunately the configuration property inside OverlayContainerViewController is private so I can't call it.

As a quick workaround you could declare configuration as private(set) which allows reading the variable.

I want to detect when moveOverlay()'s animation done

I want to make OverlayContainerViewController's dismiss animation

the animation would be like this : when NavigationVC stack's size became to 0, OverlayContainerViewController is going to call moveOverlay() with zero index of notch's height and I want to remove the OverlayViewController when the moveOverlay's animation is done

But translationController?.moveOverlay hasn't completionHandler should I add a completionHadnler manually? or there is another way to detect when moveOverlay()'s animation is done ?

Is there a way to define the starting notch position?

Is there a way for me to specify that i want the OverlayContainerViewController to begin at notch position x e.g. if i have 3 notches, min, med, max - can i specify that i want it to start at the med notch and not the min?

Awesome library by the way!

Stopping at top

In the MapsLikeViewController-Example with an iPhone 6S and changing the notch heights to

    private func notchHeight(for notch: OverlayNotch, availableSpace: CGFloat) -> CGFloat {
        switch notch {
        case .maximum:
            return availableSpace * 9 / 10
        case .minimum:
            return availableSpace * 1 / 4
        }
    }

the scrolling of the tableview is not followed through, it stops at the top notch and the tableview does not begin to scroll. First rounding the notch values (or cast to Int and back to CGFloat) solves the problem.

Untitled.mov.zip

Corner radius?

I'm having a hard time figuring out where to make the overlay controller have a corner radius. Can you point me in the right direction?

Missing param in willEndDraggingOverlay delegate call

In an older version, you used to pass the transitionCoordinator. I use this to match animations when the overlay is animating to a notch. Your comments still reference the transitionCoordinator but it is missing in the call function see below.

/// Tells the delegate when the user finishs dragging the overlay view controller with the specified velocity.
///
/// - parameter containerViewController: The container requesting this information.
/// - parameter overlayViewController: The current top overlay view controller.
/// - parameter transitionCoordinator: The transition coordinator object associated with the translation end.
func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,
willEndDraggingOverlay overlayViewController: UIViewController,
atVelocity velocity: CGPoint)

Not working properly when added source folder directly without installling pods

Hello sir,
child.didMove(toParentViewController: self) and child.didMove(toParent: self) are these both the same?. i am getting error and in child.didMove(toParent: self) so i renamed it to child.didMove(toParentViewController: self) .but i am getting other issue when i added this in my app.
i am not able to drag back ground map view but scroll view is scrolling.

when i installed using pods,drag is working fine.
but when i directly add source folder,its not working.please help.

Is there a way to animate the OverlayContainer alongside another animation?

I've seen the examples/comments for how to animate another object alongside the animation of the OverlayContainer, e.g fade in backdrop based on the height of the drawer. But is there a way to animate the height of the drawer based on another animation?

In my case, I have a UINavigationController in the container, and when I navigate from one view to another (inside the container), the origin- and the destination-viewControllers may have different "preferred" notches, so I want to animate the height of the drawer to perfectly match the transition from "origin-notch" to "destination-notch" along the navigation animation. This include when the user swipes back, which is done using a transitionCoordinator and a context (e.g no set duration).

The only way I've found to go from one notch to another is to call moveOverlay(toNotchAt:Int, animated:Bool, which won't work in this case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.