Предотвратить закрытие UIView (слайд в меню) после одного нажатия, но разрешить вставку после одного нажатия - PullRequest
0 голосов
/ 06 марта 2020

У меня есть UIView, который скользит из Botton после того, как вы 1) коснитесь или 2) переместите его наверх. Прямо сейчас вы можете закрыть его, 1) коснитесь его снова или 2) сдвиньте его вниз.

Я хочу запретить: Закрыть вид после одного нажатия и разрешить только чтобы сдвинуть его вниз, чтобы закрыть.

Это мой текущий код: (с: https://www.swiftkickmobile.com/building-better-app-animations-swift-uiviewpropertyanimator)

/// A pan gesture that enters into the `began` state on touch down instead of waiting for a touches moved event.
class InstantPanGestureRecognizer: UIPanGestureRecognizer {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
    if (self.state == UIGestureRecognizer.State.began) { return }
    super.touchesBegan(touches, with: event)
    self.state = UIGestureRecognizer.State.began
   }
}



@objc private func popupViewPanned(recognizer: UIPanGestureRecognizer) {
    print(recognizer.state.rawValue)

    switch recognizer.state {
    case .began:

        // Start the animations
        animateTransitionIfNeeded(to: currentState.opposite, duration: 0.5)

        // Pause all animations, since the next event may be a pan changed
        runningAnimators.forEach { $0.pauseAnimation() }

        // Keep track of each animator's progress
        animationProgress = runningAnimators.map { $0.fractionComplete }

    case .changed:

        // Variable setup
        let translation = recognizer.translation(in: popupView)

        if UIDevice().userInterfaceIdiom == .phone {
            switch UIScreen.main.nativeBounds.height {
            case 1334, 1920, 2208:
                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]
                }

            case 2436, 2688, 1792:
                var fraction = -translation.y / popupOffsetNotch
                // 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]
                }

            default:
                var fraction = -translation.y / popupOffsetNotch
                // 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]
                }
            }
        }

    case .ended:

        // variable setup
        let yVelocity = recognizer.velocity(in: popupView).y
        let shouldClose = yVelocity > 0

        // if there is no motion, continue all animations and exit early
        if yVelocity == 0 {
            runningAnimators.forEach { $0.continueAnimation(withTimingParameters: nil, durationFactor: 0) }
            break
        }

        // reverse the animations based on their current state and pan motion
        switch currentState {
        case .open:
            if !shouldClose && !runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
            if shouldClose && runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
        case .closed:
            if shouldClose && !runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
            if !shouldClose && runningAnimators[0].isReversed { runningAnimators.forEach { $0.isReversed = !$0.isReversed } }
        }

        // continue all animations
        runningAnimators.forEach { $0.continueAnimation(withTimingParameters: nil, durationFactor: 0) }

    default:
        ()
    }
}




/// Animates the transition, if the animation is not already running.
private func animateTransitionIfNeeded(to state: State, duration: TimeInterval) {

    // ensure that the animators array is empty (which implies new animations need to be created)
    guard runningAnimators.isEmpty else { return }

    // an animator for the transition
    let transitionAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1, animations: {
        switch state {
        case .open:
            self.bottomConstraint.constant = 0
            self.popupView.layer.cornerRadius = 10
        case .closed:
            if UIDevice().userInterfaceIdiom == .phone {
                switch UIScreen.main.nativeBounds.height {
                case 1334, 1920, 2208:
                    self.bottomConstraint.constant = self.popupOffset

                case 2436, 2688, 1792:
                    self.bottomConstraint.constant = self.popupOffsetNotch

                default:
                    self.bottomConstraint.constant = self.popupOffsetNotch
                }
            }
            self.popupView.layer.cornerRadius = 5
        }
        self.view.layoutIfNeeded()
    })

    // the transition completion block
    transitionAnimator.addCompletion { position in

        // update the state
        switch position {
        case .start:
            self.currentState = state.opposite
        case .end:
            self.currentState = state
        case .current:
            ()
        @unknown default:
            return
        }

        // manually reset the constraint positions
        switch self.currentState {
        case .open:
            self.bottomConstraint.constant = 0
        case .closed:
            if UIDevice().userInterfaceIdiom == .phone {
                switch UIScreen.main.nativeBounds.height {
                case 1334, 1920, 2208:
                    self.bottomConstraint.constant = self.popupOffset

                case 2436, 2688, 1792:
                    self.bottomConstraint.constant = self.popupOffsetNotch

                default:
                    self.bottomConstraint.constant = self.popupOffsetNotch
                }
            }
        }

        // remove all running animators
        self.runningAnimators.removeAll()
    }

    // start all animators
    transitionAnimator.startAnimation()

    // keep track of all running animators
    runningAnimators.append(transitionAnimator)
}

1 Ответ

0 голосов
/ 06 марта 2020

Решение: panRecognizer.delegate = self + UIGestureRecognizerDelegate +

 // This function is needed to add the recognizer only to its parent view.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return touch.view == gestureRecognizer.view
}

и использовать дочерние представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...