Как я могу реализовать "перетащить право, чтобы отклонить" контроллер просмотра, который находится в стеке навигации?
По умолчанию, если вы перетаскиваете правую сторону от левого края экрана, он будет перетаскивать ViewController и снимать его со стека.
Я хочу расширить эту функциональность до всего экрана. Когда пользователь тянет куда угодно, мне бы хотелось, чтобы это произошло.
Я знаю, что я могу реализовать правый жест прокрутки и просто вызвать self.navigationController?.popViewControllerAnimated(true)
Тем не менее, нет "перетаскивания" движения. Я хочу, чтобы пользователь мог перетащить контроллер вида прямо, как если бы это был объект, который показывает, что внизу. И, если он перетащит 50%, отпустите его. (Посмотрите, что я имею в виду.)
Ответы
Ответ 1
![введите описание изображения здесь]()
Сделал демонстрационный проект в Github
https://github.com/rishi420/SwipeRightToPopController
Я использовал протокол UIViewControllerAnimatedTransitioning
Из документа:
//Это используется для процентных интерактивных переходов, а также для контейнерных контроллеров...
Добавлено представление UIPanGestureRecognizer
в виде контроллера. Это действие жеста:
func handlePanGesture(panGesture: UIPanGestureRecognizer) {
let percent = max(panGesture.translationInView(view).x, 0) / view.frame.width
switch panGesture.state {
case .Began:
navigationController?.delegate = self
navigationController?.popViewControllerAnimated(true)
case .Changed:
percentDrivenInteractiveTransition.updateInteractiveTransition(percent)
case .Ended:
let velocity = panGesture.velocityInView(view).x
// Continue if drag more than 50% of screen width or velocity is higher than 1000
if percent > 0.5 || velocity > 1000 {
percentDrivenInteractiveTransition.finishInteractiveTransition()
} else {
percentDrivenInteractiveTransition.cancelInteractiveTransition()
}
case .Cancelled, .Failed:
percentDrivenInteractiveTransition.cancelInteractiveTransition()
default:
break
}
}
Шаги:
- Рассчитать процент перетаскивания в представлении
-
.Begin:
Укажите, какой сеанс выполнить и назначить делегат UINavigationController
. делегат будет необходим для InteractiveTransitioning
-
.Changed:
UpdateInteractiveTransition с процентом
-
.Ended:
Продолжить оставшееся переключение, если перетащить 50% или более или больше скорость еще отменить
-
.Cancelled, .Failed:
отменить переход
Ссылки:
Ответ 2
Swift 4 версия принятого ответа от @Warif Akhand Rishi
Хотя этот ответ работает, есть две причуды, которые я узнал об этом.
- Если вы проведете пальцем влево, он также исчезнет, как если бы вы двигались вправо.
- это также очень деликатно, потому что, если даже небольшое движение направлено в любом направлении, оно будет отклонять vc.
Кроме того, это определенно работает, и вы можете провести вправо или влево, чтобы уволить.
class ViewController: UIGestureRecognizerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.interactivePopGestureRecognizer?.delegate = self
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
view.addGestureRecognizer(panGesture)
}
@objc func handlePanGesture(_ gesture: UIPanGestureRecognizer){
let interactiveTransition = UIPercentDrivenInteractiveTransition()
let percent = max(gesture.translation(in: view).x, 0) / view.frame.width
switch gesture.state {
case .began:
navigationController?.delegate = self
navigationController?.popViewController(animated: true)
case .changed:
interactiveTransition.update(percent)
case .ended:
let velocity = gesture.velocity(in: view).x
// Continue if drag more than 50% of screen width or velocity is higher than 1000
if percent > 0.5 || velocity > 1000 {
interactiveTransition.finish()
} else {
interactiveTransition.cancel()
}
case .cancelled, .failed:
interactiveTransition.cancel()
default:break
}
}
}
Ответ 3
Вам нужно исследовать свойство interactivePopGestureRecognizer вашего UINavigationController
.
Вот аналогичный вопрос с примером кода, чтобы связать это.
UINavigationController interactivePopGestureRecognizer работает ненормально в iOS7
Ответ 4
Создайте распознаватель жестов панорамирования и переместите цели интерактивного распознавателя поп-жестов.
Добавьте свой распознаватель в контроллер push-view viewDidLoad и вуаля!
let popGestureRecognizer = self.navigationController!.interactivePopGestureRecognizer!
if let targets = popGestureRecognizer.value(forKey: "targets") as? NSMutableArray {
let gestureRecognizer = UIPanGestureRecognizer()
gestureRecognizer.setValue(targets, forKey: "targets")
self.view.addGestureRecognizer(gestureRecognizer)
}
Ответ 5
Проведите пальцем вправо, чтобы закрыть диспетчер вида
Версия Swift 5 -
(Также убрано распознавание жестов при проведении справа налево)
Важно -
В инспекторе атрибутов VC2 установите для параметра "Презентация" значение "Полноэкранный режим" в "Полноэкранный режим". Это позволит VC1 быть видимым во время отклонения VC2 с помощью жеста - без него будет черный экран позади VC2 вместо VC1.
class ViewController: UIGestureRecognizerDelegate, UINavigationControllerDelegate {
var initialTouchPoint: CGPoint = CGPoint(x: 0, y: 0)
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.interactivePopGestureRecognizer?.delegate = self
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
view.addGestureRecognizer(panGesture)
}
@objc func handlePanGesture(_ sender: UIPanGestureRecognizer) {
let touchPoint = sender.location(in: self.view?.window)
let percent = max(sender.translation(in: view).x, 0) / view.frame.width
let velocity = sender.velocity(in: view).x
if sender.state == UIGestureRecognizer.State.began {
initialTouchPoint = touchPoint
} else if sender.state == UIGestureRecognizer.State.changed {
if touchPoint.x - initialTouchPoint.x > 0 {
self.view.frame = CGRect(x: touchPoint.x - initialTouchPoint.x, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
}
} else if sender.state == UIGestureRecognizer.State.ended || sender.state == UIGestureRecognizer.State.cancelled {
if percent > 0.5 || velocity > 1000 {
navigationController?.popViewController(animated: true)
} else {
UIView.animate(withDuration: 0.3, animations: {
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
})
}
}
}
}
Надеюсь, это поможет.
Не стесняйтесь предлагать изменения в случае необходимости.
Ответ 6
С этой целью вы можете использовать жестов для прокрутки:
override func viewDidLoad() {
super.viewDidLoad()
var swipeRight = UISwipeGestureRecognizer(target: self, action: "popViewController:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
self.view.addGestureRecognizer(swipeRight)
}
func popViewController(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
self.navigationController.popViewControllerAnimated(true)
default:
break
}
}
}