Отклонить вид листа модальной формы на внешнем кране iOS 8
Я пытаюсь отклонить вид листа модальной формы на внешнем кране на iOS 8 без везения,
Я пробовал этот код
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapBehind:)];
[recognizer setNumberOfTapsRequired:1];
recognizer.cancelsTouchesInView = NO; //So the user can still interact with controls in the modal view
[self.view.window addGestureRecognizer:recognizer];
- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
CGPoint location = [sender locationInView:nil]; //Passing nil gives us coordinates in the window
//Then we convert the tap location into the local view coordinate system, and test to see if it in or outside. If outside, dismiss the view.
if (![self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil])
{
// Remove the recognizer first so it view.window is valid.
[self.view.window removeGestureRecognizer:sender];
[self dismissModalViewControllerAnimated:YES];
}
}
}
Но он не обнаруживает внешние клики, любые предложения?
Ответы
Ответ 1
В iOS 8 есть две проблемы. Во-первых, распознавание жестов не начинается.
Я решил это, добавив протокол UIGestureRecognizerDelegate
и выполнив
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
return YES;
}
Кроме того, не забудьте зарегистрировать делегат с помощью
recognizer.delegate = self;
Теперь распознаватель жестов распознает жесты, и будет вызываться целевой метод (handleTapBehind:
).
Вот вторая проблема в iOS 8: locationInView:
, похоже, не учитывает ориентацию устройства, если в качестве представления передано nil
. Вместо этого выполняется прохождение корневого представления.
Здесь мой целевой код, который работает для iOS 7.1 и 8.0:
if (sender.state == UIGestureRecognizerStateEnded) {
UIView *rootView = self.view.window.rootViewController.view;
CGPoint location = [sender locationInView:rootView];
if (![self.view pointInside:[self.view convertPoint:location fromView:rootView] withEvent:nil]) {
[self dismissViewControllerAnimated:YES completion:^{
[self.view.window removeGestureRecognizer:sender];
}];
}
}
Ответ 2
В iOS 8 вы можете посмотреть новый класс UIPresentationController
. Это дает вам лучший контроль над контейнером вокруг вашего пользовательского представления диспетчера представлений (позволяя вам правильно добавить собственный распознаватель жестов).
Вот ссылка на довольно простой учебник: http://dativestudios.com/blog/2014/06/29/presentation-controllers/
Затем добавьте затемнение для уменьшения яркости:
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.dimmingView addGestureRecognizer:singleFingerTap];
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
Ответ 3
Swift 3.1 решение, которое работает как в портретной, так и в альбомной ориентации.
class TapBehindModalViewController: UIViewController, UIGestureRecognizerDelegate {
private var tapOutsideRecognizer: UITapGestureRecognizer!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if(self.tapOutsideRecognizer == nil) {
self.tapOutsideRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTapBehind))
self.tapOutsideRecognizer.numberOfTapsRequired = 1
self.tapOutsideRecognizer.cancelsTouchesInView = false
self.tapOutsideRecognizer.delegate = self
self.view.window?.addGestureRecognizer(self.tapOutsideRecognizer)
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if(self.tapOutsideRecognizer != nil) {
self.view.window?.removeGestureRecognizer(self.tapOutsideRecognizer)
self.tapOutsideRecognizer = nil
}
}
func close(sender: AnyObject) {
self.dismiss(animated: true, completion: nil)
}
// MARK: - Gesture methods to dismiss this with tap outside
func handleTapBehind(sender: UITapGestureRecognizer) {
if (sender.state == UIGestureRecognizerState.ended) {
let location: CGPoint = sender.location(in: self.view)
if (!self.view.point(inside: location, with: nil)) {
self.view.window?.removeGestureRecognizer(sender)
self.close(sender: sender)
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}