Обработка представлений прокрутки с (настраиваемым, интерактивным) представлением и отклонением контроллера представления - PullRequest
0 голосов
/ 25 апреля 2018

Я экспериментировал с настраиваемым представлением и отклонением настраиваемого интерактивного контроллера представления (используя комбинацию UIPresentationController, UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning и UIViewControllerTransitioningDelegate) и в основном добился того, чтобы все работало хорошо для моих нужд.

Однако есть один общий сценарий, который мне еще предстоит найти в любом из учебных пособий или документации, который я прочитал, что приводит меня к следующему вопросу:

...

Как правильно обрабатывать отклонение настраиваемого интерактивного контроллера представления с помощью жеста панорамирования, когда отклоненное представление содержит UIScrollView (т. Е. UITableView, UICollectionView, WKWebView и т. Д.)?

...

По сути, я хотел бы получить следующее:

  1. Контроллеры вида в интерактивном режиме отключаются путем панорамирования их вниз. Это обычный UX во многих приложениях.

  2. Если контроллер отклоненного представления содержит (прокручиваемый по вертикали) вид прокрутки, прокрутка вниз прокручивает это представление, как ожидается, до тех пор, пока пользователь не достигнет вершины, после чего прокрутка прекращается и происходит панорамирование для увольнения.

  3. В противном случае представления прокрутки должны вести себя как обычно.

Я знаю, что это технически возможно - я видел это в других приложениях, таких как Overcast и собственное музыкальное приложение Apple, - но я не смог найти ключ к координации поведения моего жеста панорамирования с этим видом прокрутки.

Большинство моих собственных попыток сосредоточены на попытках условно включить / отключить представление прокрутки (или связанный с ним распознаватель жестов панорамирования) на основе его contentOffset.y во время прокрутки и получения оттуда распознавателя панорамирования жестов при увольнении контроллера представления, но это был полон проблем, и я боюсь, что я обдумываю это.

Мне кажется, что секрет в основном заключается в следующем методе делегата распознавания жестов панорамирования:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
   // ...
}

Я создал уменьшенный пример проекта, который должен более четко демонстрировать сценарий. Любые предложения кода приветствуются!

https://github.com/Darchmare/SlidePanel-iOS

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Для меня этот небольшой кусочек кода ответил на многие мои проблемы и очень помог моим настраиваемым переходам в просмотрах прокрутки: он будет удерживать отрицательное смещение прокрутки при перемещении при попытке начать переход или показывать индикатор активности сверху. Я предполагаю, что это решит по крайней мере некоторые из ваших проблем с переходом / анимацией:

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    if scrollView.contentOffset.y < -75 {

        scrollView.contentInset.top = -scrollView.contentOffset.y

    }
    // Do animation or transition
}
0 голосов
/ 27 апреля 2018

Решение

  • Заставьте scrollView остановить прокрутку после того, как она достигла вершины, используя свойство отказов UIScrollView и scrollViewDidScroll (_:) метод.

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

    Не забудьте установить scrollView.delegate = self

  • Обрабатывать panGestureRecognizer только тогда, когда scrollView достигает вершины - Это означает, когда scrollView.contentOffset.y == 0 с использованием протокола.

    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;
        }
      }
    }
    

Результат

enter link description here

Для более подробной информации, вы можете посмотреть мой пример проекта

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