Handling scroll views with (custom, interactive) view controller presentation and dismissal

前端 未结 2 676
臣服心动
臣服心动 2020-12-28 07:58

I have been experimenting with custom interactive view controller presentation and dismissal (using a combination of UIPresentationController, UIPercentDr

相关标签:
2条回答
  • 2020-12-28 08:51

    For me, this little bit of code answered a lot of my issues and greatly helped my custom transitions in scrollviews, it will hold a negative scrollview offset from moving while trying to start a transition or showing an activity indicator on the top. My guess is that this will solve at least some of your transition/animation hiccups:

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    
        if scrollView.contentOffset.y < -75 {
    
            scrollView.contentInset.top = -scrollView.contentOffset.y
    
        }
        // Do animation or transition
    }
    
    0 讨论(0)
  • 2020-12-28 08:57

    Solution

    • Make scrollView stop scrolling after it reached top by using UIScrollView's bounces property and scrollViewDidScroll(_:) method.

      func scrollViewDidScroll(_ scrollView: UIScrollView) {
          scrollView.bounces = (scrollView.contentOffset.y > 10);
      }
      

      Don't forget to set scrollView.delegate = self

    • Only handle panGestureRecognizer when scrollView reached top - It means when scrollView.contentOffset.y == 0 by using a protocol.

      protocol PanelAnimationControllerDelegate {
          func shouldHandlePanelInteractionGesture() -> Bool
      }
      

      ViewController

      func shouldHandlePanelInteractionGesture() -> Bool {
          return (scrollView.contentOffset.y == 0);
      }
      

      PanelInteractionController

      class PanelInteractionController: ... {
      
        var startY:CGFloat = 0
      
        private weak var viewController: (UIViewController & PanelAnimationControllerDelegate)?
      
        @objc func handlePanGestureRecognizer(_ gestureRecognizer: UIPanGestureRecognizer) {
          switch gestureRecognizer.state {
          case .began:
            break
          case .changed:
            let translation    = gestureRecognizer.translation(in: gestureRecognizer.view!.superview!)
            let velocity    = gestureRecognizer.velocity(in: gestureRecognizer.view!.superview)
            let state      = gestureRecognizer.state
      
            // Don't do anything when |scrollView| is scrolling
            if !(viewController?.shouldHandlePanelInteractionGesture())! && percentComplete == 0 {
              return;
            }
      
            var rawProgress    = CGFloat(0.0)
      
            rawProgress    = ((translation.y - startTransitionY) / gestureRecognizer.view!.bounds.size.height)
      
            let progress    = CGFloat(fminf(fmaxf(Float(rawProgress), 0.0), 1.0))
      
            if abs(velocity.x) > abs(velocity.y) && state == .began {
              // If the user attempts a pan and it looks like it's going to be mostly horizontal, bail - we don't want it... - JAC
              return
            }
      
            if !self.interactionInProgress {
              // Start to pan |viewController| down
              self.interactionInProgress = true
              startTransitionY = translation.y;
              self.viewController?.dismiss(animated: true, completion: nil)
            } else {
              // If the user gets to a certain point within the dismissal and releases the panel, allow the dismissal to complete... - JAC
              self.shouldCompleteTransition = progress > 0.2
      
              update(progress)
            }
          case .cancelled:
            self.interactionInProgress = false
            startTransitionY = 0
      
            cancel()
          case .ended:
            self.interactionInProgress = false
            startTransitionY = 0
      
            if self.shouldCompleteTransition == false {
              cancel()
            } else {
              finish()
            }
          case .failed:
            self.interactionInProgress = false
            startTransitionY = 0
      
            cancel()
          default:
            break;
          }
        }
      }
      

    Result

    enter link description here

    For more detail, you can take a look at my sample project

    0 讨论(0)
提交回复
热议问题