PaoloCuscela / Cards

Awesome iOS 11 appstore cards in swift 5.
MIT License
4.21k stars 275 forks source link

Dismiss detail view controller by scrolling on content #107

Open arinasawa opened 5 years ago

arinasawa commented 5 years ago

Is there a way to dismiss the detail view controller only by performing a gesture on the image view rather than the whole content of the detail view controller?

PaoloCuscela commented 5 years ago

Actually, I don't think so. You can try preventing user interaction in the scroll view of DetailViewController file, and then call dismiss() on backroungIV view pan gesture. Let me know if you're having troubles ;)

arinasawa commented 5 years ago

I can’t seem to figure out how to do what you said above? Do you have any example code that can achieve this?

PaoloCuscela commented 5 years ago

Forgive me if I have expressed myself badly, english isn't my first language. Anyway, the detail view controller's view is composed of a scrollview that contains the card content on top and the view managed by a 3rd ViewController below. So actually there isn't a way to do what you asked for, but you can try to achieve this by playing with the scroll view Delegate methods:

// Line 176 //MARK: - ScrollView Behaviour
extension DetailViewController: UIScrollViewDelegate {

  public func scrollViewDidScroll(_ scrollView: UIScrollView) {

        let y = scrollView.contentOffset.y
        let offset = scrollView.frame.origin.y - scrollViewOriginalYPosition

        // Behavior when scroll view is pulled down
        if (y<0) {
            scrollView.frame.origin.y -= y/2
            scrollView.contentOffset.y = 0

          // Behavior when scroll view is pulled down and then up
        } else if ( offset > 0) {

            scrollView.contentOffset.y = 0
            scrollView.frame.origin.y -= y/2
        }

        card.delegate?.cardDetailIsScrolling?(card: card)
    }

    public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

        let offset = scrollView.frame.origin.y - scrollViewOriginalYPosition

        // Pull down speed calculations
        let max = 4.0
        let min = 2.0
        var speed = Double(-velocity.y)
        if speed > max { speed = max }
        if speed < min { speed = min }
        speed = (max/speed*min)/10

        guard offset < 60 else { dismissVC(); return }
        guard offset > 0 else { return }

        // Come back after pull animation
        UIView.animate(withDuration: speed, animations: {
            scrollView.frame.origin.y = self.scrollViewOriginalYPosition
            self.scrollView.contentOffset.y = 0
        })
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

        let offset = scrollView.frame.origin.y - scrollViewOriginalYPosition
        guard offset > 0 else { return }

        // Come back after pull animation
        UIView.animate(withDuration: 0.1, animations: {
            scrollView.frame.origin.y = self.scrollViewOriginalYPosition
            self.scrollView.contentOffset.y = 0
        })
    }

}

Some tips: You could try to save the position of the first touch and block the scroll in the scrollviewdidscroll() method if the offset is > 0 and the starting position is inside the card content (BackgroundIV)

arinasawa commented 5 years ago

OK because I am trying t get the card animation to look exactly like that on the app store where you can only dismiss the detail view controller by scrolling on the image view, no the whole content because then the user can easily/accidentally dismiss the view controller.