Могу ли я сделать UIPresentationController иметь userInteractionEnabled на PresentingViewController?
Я создаю пользовательский графический интерфейс для универсального приложения для iPhone и iPad. На iPad он в значительной степени опирается на "sideViews" для таких утилит, как манипулирование контентом, detailInformation и т. П. (Вспомним расширенный SplitView). С визуальной точки зрения новый UIPresentationController позволяет мне представить эти "боковые виды" (без использования dimmedView), и его реализация проста в создании и обслуживании, и в то же время прекрасно интегрируется с раскадровкой. Но мне нужно иметь возможность манипулировать содержимым presentingViewController, когда представленный ViewController является видимым. Поэтому мой вопрос заключается в том, могу ли я установить userInteractionEnabled (или аналогичный) для presentingViewController при представлении боковых представлений?
4 ответа
UIPresentationController
вставляет свой контейнерный вид в качестве подпредставления окна над представлением представления, таким образом, любые касания за пределами представленного представления захватываются представлением контейнера и никогда не попадают в представление представления.
Исправление заключается в том, чтобы вставить представление в контейнерное представление, которое проходит через касания в представление представления. Вы можете использовать это как вид затемнения или установить его backgroundColor
в [UIColor clearColor]
для полностью прозрачного просмотра. Установите сквозные представления в коде контроллера презентаций.
@interface IVPasserView : UIView
@property (strong, nonatomic) NSArray* passthroughViews;
@end
@implementation IVPasserView
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* hit = [super hitTest:point withEvent:event];
if (hit == self)
for (UIView* passthroughView in _passthroughViews)
{
hit = [passthroughView hitTest:[self convertPoint:point toView:passthroughView]
withEvent:event];
if (hit)
break;
}
return hit;
}
@end
Примечание: пока это нарушает дух -[UIView hitTest:withEvent:]
в том, что он не возвращает подпредставление, это на самом деле, как стандарт системы UIPopoverPresentationController
обрабатывает это. Если вы установите passthroughViews
свойство там, представление контейнера отвечает hitTest:withEvent:
с сквозным видом, даже если они не супервизор / подпредставление! Таким образом, он может выжить в следующем выпуске iOS.
Модальная презентация не подходит для вашей ситуации. Лучше реализовать ваш сценарий с помощью настраиваемого контроллера представления контейнера и переопределения showDetailViewController:sender:
метод для обработки представления дополнительных контроллеров представления. Вы можете адаптировать этот метод для отображения модального контроллера представления на iPhone и справа на iPad, например.
Вот выдержка из документации Apple:
Представление против показа контроллера представления
Класс UIViewController предлагает два способа отображения контроллера представления:
Методы showViewController:sender: и showDetailViewController:sender: предлагают наиболее адаптивный и гибкий способ отображения контроллеров представления. Эти методы позволяют представителю представления решить, как лучше всего обрабатывать презентацию. Например, контроллер представления контейнера может включать контроллер представления как дочерний элемент вместо представления его модально. Поведение по умолчанию представляет контроллер представления модально. PresentViewController: animated: завершение: метод всегда отображает контроллер представления модально. Контроллер представления, который вызывает этот метод, может в конечном итоге не обрабатывать презентацию, но презентация всегда модальная. Этот метод адаптирует стиль представления для горизонтально компактных сред. Методы showViewController:sender: и showDetailViewController:sender: являются предпочтительным способом инициирования презентаций. Контроллер представления может вызывать их, ничего не зная об остальной части иерархии контроллера представления или текущем положении контроллера представления в этой иерархии. Эти методы также упрощают многократное использование контроллеров представления в различных частях вашего приложения без написания условных путей кода.
Итак, похоже, что идея UIPresentationController НЕ в том, чтобы использовать его как расширенный SplitView (или, по крайней мере, это мой текущий вывод). Мне все-таки удалось найти обходной путь. Если кто-нибудь найдет лучший способ справиться с этим, пожалуйста, дайте мне знать в комментариях.
Поэтому я вставляю представление PresentingViewController в контейнерное представление transitionContexts (так же, как контейнерное представление UIPresentationControllers) в индекс 0. Это позволяет мне прозрачно обрабатывать touchEvents в представлении PresentingViewControllers. Но он удаляет представление PresentingViewControllers из исходной иерархии представлений, поэтому мне нужно переместить его туда, когда презентация отклоняется. Это означает возвращение представления обратно к представлению parentViewController, если оно присутствует, или к окну приложения, если представляет ViewController, являющийся rootViewController приложения (могут быть и другие сценарии, но пока это будет сделано).
Все это делается в animateTransition в UIViewControllerAnimatedTransitioning.
Вот кусок кода:
UIView.animateWithDuration(transitionDuration(transitionContext),
delay: 0.0,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 0.5,
options: UIViewAnimationOptions.BeginFromCurrentState|UIViewAnimationOptions.AllowUserInteraction,
animations: { () -> Void in
animatingView.frame = finalFrame
}) { (finished:Bool) -> Void in
if !self.isPresentation {
if let parentViewController = backgroundVC.parentViewController {
parentViewController.view.addSubview(backgroundVC.view)
}
else if let window = (UIApplication.sharedApplication().delegate as! AppDelegate).window {
window.addSubview(backgroundVC.view)
}
fromView.removeFromSuperview()
}
else {
containerView.insertSubview(backgroundVC.view, atIndex: 0)
}
transitionContext.completeTransition(true)
}
Адаптация отличного решения Objective C от Глена Лоу к Swift.
// View that supports forwarding hit test touches to the provided array of views
class TouchForwardView: UIView {
// Array of views that we want to forward touches to
var touchForwardTargetViews = [UIView]()
// Variable to quickly disable/enable touch forwarding functionality
var touchForwardingEnabled = true
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// Get the hit test view
let hitTestView = super.hitTest(point, with: event)
// Make sure the hit test view is self and that touch forwarding is enabled
if hitTestView == self && touchForwardingEnabled {
// Iterate the hit test target views
for targetView in touchForwardTargetViews {
// Convert hit test point to the target view
let convertedPoint = convert(point, to: targetView)
// Verify that the target view can receive the touch
if let hitTargetView = targetView.hitTest(convertedPoint, with: event) {
// Forward the touch to the target view
return hitTargetView
}
}
}
// Return the original hit test view - this is the super value - our implmentation didn't affect the hit test pass
return hitTestView
}
}