Iphone SDK Abweisung Modal Viewcontrollers auf ipad von außen darauf klicken
-
26-09-2019 - |
Frage
Ich mag eine FormSheetPresentation modal View-Controller entlassen, wenn die Benutzer Hähne außerhalb der modalen Ansicht ... Ich habe eine Reihe von Anwendungen gesehen, aber ich kann nicht herausfinden, wie da die unter Ansichten sind Behinderte aus berührt, wenn modale Ansichten wie diese angezeigt werden (werden sie es als popover präsentiert vielleicht?) ... jemand irgendwelche Vorschläge?
Lösung
Ich bin ein Jahr zu spät, aber das ist ziemlich einfach zu tun.
Haben Sie Ihre modal View-Controller eine Gestenerkenner an das Fenster der Ansicht anhängen:
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];
[recognizer release];
Der Umgang Code:
- (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's location into the local view's coordinate system, and test to see if it's 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's view.window is valid.
[self.view.window removeGestureRecognizer:sender];
[self dismissModalViewControllerAnimated:YES];
}
}
}
Das ist es. HIG verdammt wird, ist dies ein nützliches und oft intuitives Verhalten ist.
Andere Tipps
Die anderen Anwendungen sind nicht Modal mit Ansichten, wenn sie der Ansicht zulassen, indem Sie außerhalb davon zu entlassen. UIModalPresentationFormSheets
kann nicht auf diese Weise zurückzuweisen. (Noch, in der Tat kann jeder UIModal in SDK3.2). Nur der UIPopoverController
kann durch Klicken außerhalb des Bereichs abzuweisen. Es ist durchaus möglich (wenn auch gegen Apples iPad HIG) für den App-Entwickler, um den Hintergrund-Bildschirm hat beschattet und angezeigt dann die UIPopoverController
so dass es wie ein UIModalPresentationFormSheets
(oder anderes UIModal View) aussieht.
[...] UIModalPresentationCurrentContext Stil lässt einen View-Controller die Präsentation Stil seiner Eltern übernehmen. In jeder modalen Ansicht zeigen die gedimmt Bereiche die zugrunde liegenden Inhalte aber nicht Abgriffe in diesen Inhalten ermöglichen. Deshalb, im Gegensatz zu einem popover, Ihre modal Ansichten müssen noch Kontrollen haben, die dem Benutzer erlauben, die modale Ansicht zu schließen.
Sehen Sie die iPadProgrammingGuide auf der Entwickler-Website für weitere Informationen (Seite 46 - „Konfigurieren der Präsentationsstil für Modal Views“)
Für iOS 8, müssen Sie sowohl die UIGestureRecognizer
implementieren, und tauschen Sie das (x, y) Koordinaten der angezapften Lage, wenn in Querformat. Nicht sicher, ob dies zu einem iOS 8 Fehler zurückzuführen ist.
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// add gesture recognizer to window
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];
recognizer.delegate = self;
}
- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded) {
// passing nil gives us coordinates in the window
CGPoint location = [sender locationInView:nil];
// swap (x,y) on iOS 8 in landscape
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
location = CGPointMake(location.y, location.x);
}
}
// convert the tap's location into the local view's coordinate system, and test to see if it's 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's view.window is valid
[self.view.window removeGestureRecognizer:sender];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
}
#pragma mark - UIGestureRecognizer Delegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return YES;
}
Der obige Code funktioniert super, aber ich würde die if-Anweisung ändern,
if (!([self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil] || [self.navigationController.view pointInside:[self.navigationController.view convertPoint:location fromView:self.navigationController.view.window] withEvent:nil]))
{
// Remove the recognizer first so it's view.window is valid.
[self.view.window removeGestureRecognizer:sender];
[self dismissModalViewControllerAnimated:YES];
}
Dies stellt sicher, können Sie immer noch interact mit der Navigationsleiste, sonst Antippen der modale Ansicht entlässt.
Antwort für iOS aktualisiert 8
Offenbar in iOS 8, die UIDimmingView
hat einen Anzapfung Gestenerkenner, die interferiert mit der ersten Implementierung, so dass wir es ignorieren und es nicht scheitern müssen.
Dies ist das Zeitalter der Geschwindigkeit, die meisten sind so wahrscheinlich Kopieren Sie einfach den Code oben .. Aber ich leiden unter OCD, wenn es um Code kommt, leider.
Hier ist eine modulare Lösung, die Danilo Campos Antwort verwendet mit Kategorien . Es ist auch löst ein wichtiger Fehler, die auftreten können, wenn Sie Ihre modal durch andere Mittel zu entlassen, wie erwähnt .
. Hinweis: Die if-Anweisungen sind da, weil ich die View-Controller für iPhone und iPad, und nur das iPad muss / unregister registrieren
Very important:
Wenn Sie irgendeine andere Art und Weise müssen schließen Sie Ihren modalen Popup-Fenster , vergessen Sie nicht den Hahn Gestenerkenner zu entfernen!
Ich habe vergessen, dies und bekam verrückt Abstürze später, da der Hahn Erkennungs immer noch Ereignisse feuern.
Nach Apples iOS HIG, 1. die modale Ansicht nicht über diese Fähigkeit ohne Eingabe auf sich selbst entlassen zu werden; 2. Verwenden modalen Ansicht in der Situation, dass eine Benutzereingabe erforderlich ist.
Verwenden UIPresentationController statt:
- (void)presentationTransitionWillBegin
{
[super presentationTransitionWillBegin];
UITapGestureRecognizer *dismissGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(dismissGestureTapped:)];
[self.containerView addGestureRecognizer:dismissGesture];
[[[self presentedViewController] transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
} completion:nil];
}
- (void) dismissGestureTapped:(UITapGestureRecognizer *)sender{
if (sender.state==UIGestureRecognizerStateEnded&&!CGRectContainsPoint([self frameOfPresentedViewInContainerView], [sender locationInView:sender.view])) {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
}
Geändert von LookInside Beispiel
Dies funktioniert für mich für ios7 eine 8 und Navigationsleiste.
Wenn Sie nicht über die Navigationsleiste müssen nur entfernen location2 und zweite Bedingung in der if-Anweisung nach den Rohren.
@MiQUEL sollte dies auch für Sie arbeiten
- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
CGPoint location1 = [sender locationInView:self.view];
CGPoint location2 = [sender locationInView:self.navigationController.view];
if (!([self.view pointInside:location1 withEvent:nil] || [self.navigationController.view pointInside:location2 withEvent:nil])) {
[self.view.window removeGestureRecognizer:self.recognizer];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
}
Edit: Sie können auch eine Gestenerkenner Delegat für diese und andere oben genannten Lösungen zur Arbeit sein müssen. Machen Sie es wie so:
@interface CommentTableViewController () <UIGestureRecognizerDelegate>
setzen Sie sich als Delegierter für den Erkenner:
self.recognizer.delegate = self;
und implementieren diese Delegatmethode:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
Es ist ziemlich machbar.
Werfen Sie einen Blick hier
https://stackoverflow.com/a/26016458/4074557
Es ist ein Navigation (modal), dass Auto für ipad entlassen (wenn Sie außerhalb tippen)
Verwenden des Viewcontroller im Innern.
Hope es hilft.
Ich weiß, es ist spät, aber denken Sie daran mit CleanModal (getestet mit iOS 7 und 8).
Sie können mit MZFormSheetController wie folgt aus:
MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithSize:customSize viewController:presentedViewController];
formSheet.shouldDismissOnBackgroundViewTap = YES;
[presentingViewController mz_presentFormSheetController:formSheet animated:YES completionHandler:nil];
In Swift 2 / Xcode Version 7.2 (7C68) der folgende Code für mich gearbeitet.
Achtung: Dieser Code soll, hier in der ViewController.swift Datei des dargebotenen Formblatt oder Seite Blattes gestellt werden: „PageSheetViewController.swift“
class PageSheetViewController: UIViewController, UIGestureRecognizerDelegate {
override func viewDidAppear(animated: Bool) {
let recognizer = UITapGestureRecognizer(target: self, action:Selector("handleTapBehind:"))
recognizer.delegate = self
recognizer.numberOfTapsRequired = 1
recognizer.cancelsTouchesInView = false
self.view.window?.addGestureRecognizer(recognizer)
}
func gestureRecognizer(sender: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
return true
}
func handleTapBehind(sender:UIGestureRecognizer) {
if(sender.state == UIGestureRecognizerState.Ended){
var location:CGPoint = sender.locationInView(nil)
// detect iOS Version 8.0 or greater
let Device = UIDevice.currentDevice()
let iosVersion = Double(Device.systemVersion) ?? 0
let iOS8 = iosVersion >= 8
if (iOS8) {
// in landscape view you will have to swap the location coordinates
if(UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation)){
location = CGPointMake(location.y, location.x);
}
}
if(!self.view.pointInside(self.view.convertPoint(location, fromView: self.view.window), withEvent: nil)){
self.view.window?.removeGestureRecognizer(sender)
self.dismissViewControllerAnimated(true, completion: nil)
}
}
}
}