GithubHelp home page GithubHelp logo

harshilshah / decktransition Goto Github PK

View Code? Open in Web Editor NEW
2.2K 34.0 168.0 2.53 MB

A library to recreate the iOS Apple Music now playing transition

License: MIT License

Ruby 3.60% Swift 94.98% Objective-C 0.72% Shell 0.69%
ios modals apple-music transition

decktransition's Introduction

DeckTransition

CI Status Version Package Managers Documentation License Contact

DeckTransition is an attempt to recreate the card-like transition found in the iOS 10 Apple Music and iMessage apps.

Hereʼs a GIF showing it in action.

Demo

Requirements

  • Swift 5.0
  • iOS 9 or later

Installation

CocoaPods

To install DeckTransition using CocoaPods, add the following line to your Podfile:

pod 'DeckTransition', '~> 2.0'

Carthage

To install DeckTransition using Carthage, add the following line to your Cartfile:

github "HarshilShah/DeckTransition" ~> 2.0

Documentation

You can find the docs here. Documentation is generated with Jazzy, and hosted on GitHub Pages.

Usage

Basics

Set modalPresentationCapturesStatusBarAppearance to true in your modal view controller, and override the preferredStatusBarStyle variable to return .lightContent.

Additionally, the UIScrollView instances which should be tracked for the swipe-to-dismiss gesture should have their backgroundColor set to .clear.

Presentation

The transition can be called from code or using a storyboard.

To use via storyboards, just setup a custom segue (kind set to custom), and set the class to DeckSegue.

Hereʼs a snippet showing usage via code. Just replace ModalViewController() with your view controller's class and youʼre good to go.

let modal = ModalViewController()
let transitionDelegate = DeckTransitioningDelegate()
modal.transitioningDelegate = transitionDelegate
modal.modalPresentationStyle = .custom
present(modal, animated: true, completion: nil)

Dismissal

By default, DeckTransition has a swipe-to-dismiss gesture which is automatically enabled when your modalʼs main UIScrollView is scrolled to the top.

You can opt-out of this behaviour by passing in false for the isSwipeToDismissEnabled parameter while initialising your DeckTransitioningDelegate.

UIScrollView detection

DeckTransition has an internal heuristic to determine which UIScrollView should be tracked for the swipe-to-dismiss gesture. In general, this should be sufficient for and cover most use cases.

However there are some edge cases, and should you run into one, these can we worked around by making your modal view controller conform to the DeckTransitionViewControllerProtocol protocol. More information about this can be found in the documentation page about UIScrollView detection.

Snapshots

For a variety of reasons, and especially because of iOS 11's safe area layout, DeckTransition uses a snapshot of your presenting view controller's view instead of using the view directly. This view is automatically updated whenever the frame is resized.

However, there can be some cases where you might want to update the snapshot view by yourself, and this can be achieved using the following one line snippet:

(presentationController as? DeckSnapshotUpdater)?.requestPresentedViewSnapshotUpdate()

All this does is request the presentation controller to update the snapshot.

You can also choose to update snapshot directly from the presenting view controller, as follows:

(presentedViewController?.presentationController as? DeckSnapshotUpdater)?.requestPresentedViewSnapshotUpdate()

It's worth noting that updating the snapshot is an expensive process and should only be used if necessary, for example if you are updating your entire app's theme.

Apps Using DeckTransition

Feel free to submit a PR if you’re using this library in your apps

Author

Written by Harshil Shah

License

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

decktransition's People

Contributors

aehlke avatar arvindhsukumar avatar felix-dumit avatar gcox avatar giannicarlo avatar harshilshah avatar keith avatar marchy avatar zachsimone avatar zmknox 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

decktransition's Issues

Presenting View Controller on Modal View Controller removes deck effect

After presenting a modal view controller on a view controller that was presented using DeckTransition, the deck effect goes away.

How to reproduce

Take the example project, and add this code to viewDidLoad() in ModalViewController.

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
    let safariViewController = SFSafariViewController(url: URL(string: "https://www.google.com")!)
    self.present(safariViewController, animated: true, completion: nil)
}

Result

Before:
before

During presentation:
presented

After dismissal:
after

You can see in the last image that the rounded corners and inset is now gone.

Thank you for the hard work. Please let me know if there's any more information I can provide!

NavBar Glitch

This glitch appends when the View Controller is not the top-level VC of a Navigation Controller (when you've got a Back Button in the navBar etc.) When the Modal Controller is pushed, the navBar of the previous ViewController is cropped from the top.
glitch

Graphic glitch when a "full screen" view controller over the Deck Transition View is dismissed.

I have this small issue but i'd love to get rid of it if possible.
I have the Deck Transition View working properly, but If I open a "full screen" view controller over it (presented with Pop Up), when I dismiss this view controller the top side of the Deck Transition "bounces" before recalculate its height.

It seems like the Deck Transition is going "full screen" with no rounded corners, and then when it recalculates its height, it "bounce" down and restore the rounded corners.

To recreate this behaviour, just present a "full screen" view controller over the Deck Transition.

Is there a way to fix this?
Thank you.

Snapshot does not properly display when presented from a SearchController

While working on What's Open with @srct, we noticed when adding search to our app that the snapshot generated by DeckTransition just generates black when presented from a SearchController.

Here's an example: https://streamable.com/b3bcv

And here's how we're calling to present from our main view to the detail view with DeckTransition:

let destDelegate = DeckTransitioningDelegate()
destination.modalPresentationStyle = .custom
destination.transitioningDelegate = destDelegate

// present the detail view over the search controller if we're searching
if searchController.isActive {
    searchController.present(destination, animated: true, completion: nil)
}
else {
    present(destination, animated: true, completion: nil)
}

(The full code can be found at https://git.gmu.edu/srct/whats-open-ios ).

It is very possible that we're doing something wrong, but for the life of me I don't know what that may be.

White area opens up at the top while dismissing

Hi! I'm trying it out on a UITableViewController. This is the table shown from the top position:
simulator screen shot - iphone 7 plus - 2018-04-01 at 18 14 47

And this is how it looks when it is being dismissed. As you swipe down, this white area opens up and gradually grows before the modal is dismissed. Do you know what it is and how I can avoid it?
simulator screen shot - iphone 7 plus - 2018-04-01 at 18 14 45

Thanks

Breaks swipe recognizers in the scroll view

My modal view controller is a collection view controller, in which some of the cells are custom slider controls (subclasses of UIControl). Probably because of the pan gesture recognizer, the controls don't work. I use the default beginTracking, etc., UIControl methods.

What'd be the best way to handle this problem?

Is there a way to use it in swift 3?

Hey man, thanks for the library, though I still can't get it working.
I know you've mentioned swift 4 as a requirement, but I thought maybe the previous versions would work on swift 3. Is it possible? What is the version I should enter in pod file?

When I set a segue to custom and class to DeckSegue, I get this error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not create a segue of class '(null)''

StatusBar appearance doesn't change using storyboards...

In your example file you are creating an object of ModalViewController and present this view controller via present(_:animated:completion:) after transitioningDelegate and modalPresentationStyle are set. This works as expected. The statusBar appearance changes with the transition from default to lightContent and then back to default again when dismissing.

But creating a storyboard segue by following the instructions in your README file (line 51) and perform the segue by invoking performSegue(withIdentifier:sender) doesn't change the statusBar appearance as expected. It keeps its default value. I couldn't figure out why.

Tested on Xcode 9GM simulator with iOS 11, iPhone 7+8.

UITableView Not working properly.

Hey Harshil,

A Big Thanks for this Library

i've implemented this library and i'm trying to show list on the presented ViewController and for that i've implemented UITableView with all required delegates & datasources.

Issue
I found that there is a strange problem while i scroll the tableView. UITableViewCell doesn't reuses properly. while scrolling, it randomly hides UITableViewCell.

i've checked it twice that this is not the improper implementation of UITableView.

View Controller Data

Hi,

First of all: A-M-A-Z-I-N-G work!!!

But is it possible to show a view controllers data instead of the coded view?
Thanks
Eliott

Breaking main view controller animation

I have been attempting to modify the animation transition as I believe the current implementation is too harsh a transition. I have replaced the code inside animateTransition() of DeckPresentingAnimationController to:

    let convenienceAnimator = UIViewPropertyAnimator(duration: transitionDuration(using: transitionContext), dampingRatio: 1.5) {
        presentedViewController.view.frame = finalFrameForPresentedView
    }
        
    convenienceAnimator.addCompletion({ position in
        transitionContext.completeTransition(position == .end)
    })
        
    convenienceAnimator.startAnimation()

Now the presentedViewController appears much more smoothly to my liking. However, this seems to break the transition of the previous view controller moving backwards - it now just snaps back. How would I solve this issue?

Interactive Dismiss Animation

Any plans to support an interactive dismiss animation, similar to how the Apple Music apps currently works?

Thanks for this library!

Crash while scrolling into UITableView and going back on iOS 10.

Hello,
I have a crash on iOS 10. while scrolling into UITableView and going back (from a navigation controller).

Error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7ff741828400 of class UITableViewWrapperView was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x610000037b60> (
<NSKeyValueObservance 0x6100002581e0: Observer: 0x610000269e80, Key path: contentOffset, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x610000257400>

Looks like that you forget to remove observers (not setting them to nil) on ScrollViewUpdater.
You also forget to call deinit and remove observers on DeckPresentationController.

Carthage support

Hey!
Matt from WWDCSCholars here :)

You sent me this library a few days ago. It looks neat! But we were wondering, could you please add Carthage support so we can actually implement it in the app, without too much hassle?

In-Call Status Bar Issue

It seems there's two issues when there's an in-call status bar with a taller height. First, the status bar covers up the presented view controller's top part.

Second, after dismissing the presented modal, the presented view controller isn't being reset correctly. To reproduce, on the demo toggle in-call status bar, present the modal, take the app to background and bring it back. Now the presented view controller's frame is wrong. It's something to do with the transform, but I haven't figured it out yet.. On my own app, the controller's frame is actually going off screen (e.g. too large) after the modal is dismissed

Performing appearanceTransition in animation controllers can leave presenting controller in invalid state

I don't believe calling beginAppearanceTransition/endAppearanceTransition in DeckDismissingAnimationController/DeckPresentingAnimationController is the right approach. I've discovered the following problems:

  1. If the modal presented or dismissed without animation, the methods will not be called.
  2. If animation calls are unbalanced (ie. present with animation, dismiss without), the presenting controller will be left in an invalid state, where it will not receive any appearance calls at all moving forward, despite still being visible.

I tested two possible solutions:

  1. Remove the calls entirely, and instead have DeckPresentationController override shouldRemovePresentersView and return true. Downside is that it would likely interfere with refresh the snapshot.
  2. Make these calls in *transitionWillBegin/*transitionDidEnd instead. This worked just as well in my testing, but I'm not sure at which point inside these methods would be the best place, so I didn't include a PR.

Scrolling UIDatePicker dismisses modal view controller

The modal view I am displaying using DeckTransition contains a UIDatePicker, when the date picker is swiped to select a date/time this triggers the dismiss gesture. I have reproduced this using the Example project just by adding a UIDateView to the view.

Is there a work around to resolve this issue?

Table view scroll

I have implemented your scroll view code to my table view controller and it will dismiss when I’m not at the top. Do you have any suggestions?

Also when it said set the scroll view delegate as self, I just made sure tableview.delegate equaled self. Is that correct?

KeyPath observers not removed

Using version 1.0.0 installed via CocoaPods, when I dismiss a view controller that I presented with DeskTransition, I receive the following crash:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7fbb03e54680 of class UIView was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x6080002373e0> (
<NSKeyValueObservance 0x608000243e40: Observer: 0x7fbb03c56370, Key path: frame, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x608000240120>
<NSKeyValueObservance 0x608000240660: Observer: 0x7fbb03c56370, Key path: transform, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x608000243750>
)'

I believe that these key path observations in DeckPresentationController.swift are never removed via removeObserver(_:forKeyPath:):

presentedViewController.view.addObserver(self, forKeyPath: "frame", options: [.initial], context: nil)
presentedViewController.view.addObserver(self, forKeyPath: "transform", options: [.initial], context: nil)

Thanks for all of your hard work on this!

Modal not appearing in segue

Hi there.

Really want to use DeckTransition but it isn't working for me.
I'm using a dark background and an embedded UIView with a tap gesture recogniser.

Please can you help me.

Bug on hidesBarsOnTap

Hello Harshil Shah! Thanks a lot of what are you doing!!
In ios11 I found interesting bug. On hiding navigation bar on tap it disappears like on foto. Can you help with this?

screen shot 2017-12-19 at 7 53 49 pm

screen shot 2017-12-19 at 7 54 03 pm

`pod try` Support

$ pod try DeckTransition
Updating spec repositories

Trying DeckTransition
Performing CocoaPods Installation
[!] Unable to find a target named `DeckTransition_Tests`, did find `DeckTransition_Example`.

[!] Automatically assigning platform 

ModalViewController not showing

Hi, I try to use DeckTransition and the transition is working nice but the ModalViewController is not showed.
Here's a screen capture of my sample app.
img_4871

Use transition to present another view controller on custom presented controller

At the moment, when the transition is used to present a view controller on top of another view controller that already has been presented with the transition, the layout breaks.

deck-doublemodal

blackbg

I want to achieve something similar to the Overcast app where another view controller can be presented (the second view controller is shown in the back right on top of the first one).

overcast_modal

I want to implement this but I'd like to see if anyone has any advice on the best way to accomplish this. The black backgroundView is hiding what's behind it. Would I need a whole new custom transition class?

Library causes lags in animations.

I'm currently working on an app using this great library, but there's seems to be a problem.
I have main screen, which has an "open" and "close" animation, which works fine.
After implementing Deck Transition and after opening several Deck Cards over my main screen, the animation I had before starts to lag.
If I remove Deck Transition from my project, the animations works great again.

So, might there be a memory problem in this library?
How can I solve the problem?

Can't use scrollViewForDeck for Outlet Views

Crashing whenever returning a ScrollView which is added through storyBoard to the param scrollViewForDeck.(There is no issue when we add the scrollView through programmatically.)

The scrollViewForDeck param called before ViewDidLoad of presentedViewController which intends to crash with message "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"

Code Snippet:

class TestViewController: UIViewController,DeckTransitionViewControllerProtocol {

@IBOutlet weak var tableView: UITableView!

var scrollViewForDeck : UIScrollView {
    get {
        return tableView
    }
}

Dragging past threshold closes view even if finger does not let go.

I noticed that if you drag the view past the threshold to dismiss it, you can't drag your finger back if you don't let go to cancel it.

It's a bit frustrating if you drag it down to "peek" underneath, and then it closes. Just running some tests here to examine the functionality and noticed this.

Feature Request

@HarshilShah
I love but library. Would love to have the option to use it without a top-offset at all on any device.

I just it for the UX which flows better than presenting a modal and i like the swipe to dismiss gesture along with the scaling of the presenting VC.

So if you could add the option for zero Y offset, that would be cool!

What if i dont want to use background transition?

First of all thank you very much to making such a wonderful source for developers. I use that for single screen present look like following:

screen shot 2018-02-15 at 12 49 28 pm

But i want to use stack background viewcontroller stay at their position just look black overlay without gose to depth. like following screenshot:

screen shot 2018-02-15 at 12 49 08 pm

Can you let me know how do i stock transit for background viewcontrollre that stop go to depth.

Rounded corner of presenting view controller does not animate alongside dismissal

Rounded corner of the presenting view controller seems to be set back to the original quite abruptly (which does not seem to happen in the gif presented on the intro screen). Is there a way to configure this? Or is this by design?

I've gone through the code shortly, but it does not seem that it is supposed to be animated (it seems that rounded corners are rendered using this RoundedView but it did not seem that it was animated).

memory leak

deinit is not being called on the ViewController I use this ModalCardPresentationManager on.

Doesnt work well with Webview

@HarshilShah
In my VC(embeded in NavigationController) I have a UIWebView.
I set my VC as UIWebView.scrollView.delegate.

However in setting the below scrollview delegate method and the code in it, the VC still dismisses when Im scrolling dispite having content at the top to scroll to.

public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let delegate = transitioningDelegate as? DeckTransitioningDelegate {
            if scrollView.contentOffset.y > 0 {
                // Normal behaviour if the `scrollView` isn't scrolled to the top
                scrollView.bounces = true
                delegate.isDismissEnabled = false
            } else {
                if scrollView.isDecelerating {
                    // If the `scrollView` is scrolled to the top but is decelerating
                    // that means a swipe has been performed. The view and
                    // scrollviewʼs subviews are both translated in response to this.
                    view.transform = CGAffineTransform(translationX: 0, y: -scrollView.contentOffset.y)
                    scrollView.subviews.forEach {
                        $0.transform = CGAffineTransform(translationX: 0, y: scrollView.contentOffset.y)
                    }
                } else {
                    // If the user has panned to the top, the scrollview doesnʼt bounce and
                    // the dismiss gesture is enabled.
                    scrollView.bounces = false
                    delegate.isDismissEnabled = true
                }
            }
        }
    }```

Opening a new modal on top breaks the layout

Hey, first of all great library ! It really does just what I need so thank you.

However for one of my use case I have to open another modal on top of the one the lib is already presenting. I've made a small Video so you can see the issue but basicaly once you close the new modal, the 28px offset is now at the bottom and not a the top and my layout is quite weird (see the bottom blue stuff)

Changing the dismissThreshold

As it stands the dismiss swipe needs to be pretty determined. Perhaps the dismissThreshold could be configurable? Am I correct in assuming it cannot be changed without messing with the Pod source a the moment?

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.