mkko / DrawerView

A drop-in view, to be used as a drawer anywhere in your app
MIT License
375 stars 57 forks source link

Expose PanGestures #6

Closed kylebrowning closed 5 years ago

kylebrowning commented 5 years ago

You should expose the pan gestures so programmers can make their own animations based on percentages of the pan/velocity.

mkko commented 5 years ago

Thank you for your contribution. I'm curious, what is the use case exactly? I believe exposing the pan gesture resolves the issue with animations only partially, as in some cases the pan gesture is not involved in the transition.

kylebrowning commented 5 years ago

The easiest example is that If I want to create my own UIViewPropertyAnimators to change UIViews outside of the Drawer view.

Like move the X constraint of a view on my main view that has the drawer.

Another example is to fade things inside the drawer view.

Without access to the pan gestures you cannot accurately determine the percentage of pan completion

func drawerIsDragging(_ drawerView: DrawerView, with recognizer: UIPanGestureRecognizer) {
        // variable setup
        let translation = recognizer.translation(in: drawerView)
        var fraction = -translation.y / popupOffset

        // adjust the fraction for the current state and reversed state
        if currentState == .open { fraction *= -1 }
        if runningAnimators[0].isReversed { fraction *= -1 }

        // apply the new fraction
        for (index, animator) in runningAnimators.enumerated() {
            animator.fractionComplete = fraction + animationProgress[index]
        }
    }
mkko commented 5 years ago

So you'd like to get the relative position of the drawer while it's moving? Is there a specific case for detecting only dragging and not programmatic selection? The pan handler isn't being evaluated when setting the position animated in code.

There's already drawerDidMove for this purpose but do you feel there's something missing from it? Currently it gives you the offset, evaluated from the bottom (i.e. the visible height of the drawer). For this same purpose drawerOffset is updated continuously.

Also in the master branch there's a property currentChildOpacity which is a bit vaguely named, but should give you a value you can use for content opacity. It is the same value used for animating opacity when collapsed and bottom inset is set.

Does any of these work for your purposes? I'm happy to add as much support as possible for better animations.

kylebrowning commented 5 years ago

@mkko The updated offset values are fine, but can't tell which direction the pan is going without maths and more allocations

Im not looking for just content opacity Im looking to be able to move a views y frame, or transform scale a UILabel while the user is dragging the view. It's not during a programatic selection.

        let transitionAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1, animations: {
            switch state {
            case .open:
                self.drawerView.cornerRadius = 0
                self.closeButton.alpha = 1
                self.pickedSessionLabel.alpha = 0
                self.openTitleLabel.alpha = 1
                self.hammer.alpha = 0
                self.openTitleLabel.snp.remakeConstraints { snp in
                    snp.width.equalTo(70)
                    snp.centerX.equalToSuperview()
                    snp.centerY.equalToSuperview().offset(12)
                }

                self.headerView.snp.updateConstraints { snp in
                    snp.height.equalTo(84)
                }
                self.openTitleLabel.transform = .identity

            case .collapsed:
                self.closeButton.alpha = 0
                self.pickedSessionLabel.alpha = 1
                self.drawerView.cornerRadius = 16
                self.hammer.alpha = 1
                self.openTitleLabel.alpha = 0.6
                self.openTitleLabel.snp.remakeConstraints { snp in
                    snp.width.equalTo(70)
                    snp.centerX.equalToSuperview()
                    snp.top.equalToSuperview().offset(28)
                }
                self.openTitleLabel.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
            default:
                break
            }
            self.view.layoutIfNeeded()
        })

I can't get

mkko commented 5 years ago

I don't think the gesture recognizer belongs to the delegate callbacks though.

However, we could expose it as an optional property in DrawerView. I believe you can replace drawerIsDragging with drawerDidMove and check the status of the gesture recognizer, whether it is active or not. What do you think?

mkko commented 5 years ago

Hi @kylebrowning! The exposing of the pan gesture recognizer was added in another PR. I'm closing this one, but I would highly appreciate if you can give feedback whether the change works for you or not.

Thank you for efforts, despite this PR not getting merged.