Iphone SDK の外側をクリックすると、iPad 上のモーダル ViewController が削除される
-
26-09-2019 - |
質問
ユーザーがモーダルビューの外側をタップしたときに、FormSheetPresentation モーダルビューコントローラーを閉じたいです...これを行うアプリ(たとえば、iPad の eBay)をたくさん見てきましたが、その下のビューがタッチから無効になっているため、方法がわかりませんモーダルビューがこのように表示されるとき(おそらくポップオーバーとして表示されますか?)...誰か提案がありますか?
解決
私は後半年だけど、これを行うのは非常に簡単です。
あなたのモーダルビューコントローラをお持ちのビューのウィンドウにジェスチャー認識を添付します:
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];
処理コード:
- (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];
}
}
}
それについてです。 HIGは、これは便利で、多くの場合、直感的な動作であり、のろわれます。
他のヒント
他のアプリは、モーダルビューを使用していません。 UIModalPresentationFormSheets
は、この方法を却下することはできません。 (でも、実際にSDK3.2で任意のUIModal缶)。のみUIPopoverController
はエリアの外側をクリックすることで却下することができます。アプリ開発者が背景画面を網掛けし、それがUIPopoverController
(または他のUIModalビュー)のように見えるようにUIModalPresentationFormSheets
を表示していることが(AppleのiPadのHIGに対しても)非常に可能性があります。
[...] UIModalPresentationCurrentContextスタイルは、ビューコントローラは、その親のプレゼンテーションスタイルを採用することができます。各モーダルビューでは、淡色表示領域は、基礎となるコンテンツを表示するが、その内容のタップを許可していません。したがって、ポップオーバーとは異なり、あなたのモーダルビューはまだ、ユーザがモーダルビューを却下するためのコントロールを持っている必要があります。
詳細については、開発者向けサイトでiPadProgrammingGuideを参照してください(ページ46 - 「モーダルビューのためのプレゼンテーション・スタイルの設定」を参照)。
はIOSの8については、両方のUIGestureRecognizer
を実装し、タップ位置場合横向きでの座標(x、y)を交換しなければなりません。わからない、これはiOSの8のバグが原因である場合。
- (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;
}
の素晴らしい作品上記のコードが、私はにif文を変更します、
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];
}
これは、あなたがまだ相互作用のナビゲーションバーで、それ以外の場合にタップすると、モーダルビューを閉じることができますを確認します。
iOS 8 向けに回答が更新されました
どうやらiOS 8では、 UIDimmingView
にはタップ ジェスチャ認識機能があり、これが最初の実装を妨げるため、これを無視し、失敗する必要はありません。
今はスピードの時代なので、おそらくほとんどの人は上記のコードをコピーするだけでしょう。しかし、残念なことに、私はコードに関して OCD に悩まされています。
これは、カテゴリを含む Danilo Campos の回答を使用したモジュール式ソリューションです。. 。また 解決します 他の手段でモーダルを閉じている場合に発生する可能性のある重要なバグ 述べたように.
注記: if ステートメントが存在するのは、iPhone と iPad の両方でビュー コントローラーを使用しており、iPad のみを登録/登録解除する必要があるためです。
アップデート: 素晴らしいものでは正しく動作しなかったため、要点が更新されました FCオーバーレイ コードがあり、表示されたビューでジェスチャを認識できませんでした。これらの問題は修正されました。カテゴリの使用は次のように簡単です。
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.presentingViewController) {
[self registerForDismissOnTapOutside];
}
}
- (void)viewWillDisappear:(BOOL)animated
{
if (self.presentingViewController) {
[self unregisterForDismissOnTapOutside];
}
[super viewWillDisappear:animated];
}
コピーしModalViewControllerにこのコードを貼り付けます:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//Code for dissmissing this viewController by clicking outside it
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'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];
}
}
}
Very important:
あなたがのモーダルポップアップウィンドウを閉じるには、他の方法を持っている場合は、の、タップジェスチャー認識を削除することを忘れないでください!
タップ認識は、まだイベントを発射して以来、私は、これを忘れてしまった、と後にクレイジークラッシュを得ています。
は、AppleのiOSのHIGによると、1モーダルビュー自体上の任意の入力なしに却下されるという能力を持っていません。 2.ユーザーの入力が必要とされている状況でのモーダルビューを使用します。
利用UIPresentationController代わります:
- (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];
}
}
LookInsideの例から変更された。
ios7 8とナビゲーションバーのために私のためにこの作品ます。
あなたはナビゲーションバーを必要としない場合は、単にパイプの後にif文ます。
でLOCATION2及び第二の条件を削除します@MiQUEL、これはあまりにもあなたのために働く必要があります。
- (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];
}
}
}
編集:また、これと仕事に他の上記の解決策のためのジェスチャー認識デリゲートする必要があります。そのようにそれを実行します:
@interface CommentTableViewController () <UIGestureRecognizerDelegate>
は、認識のためのデリゲートとして自分自身を設定します:
self.recognizer.delegate = self;
このデリゲートメソッドを実装します:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
使い方はとても可.
くはこちらをご覧ください
https://stackoverflow.com/a/26016458/4074557
でNavigationController(モーダル)が自動解任のためのipad(タップすると外)
ご利用viewcontrollerすることが重要です。
希望です。
私はそれが遅知っているが、CleanModal(iOSの7と8でテスト)の使用を検討します。
あなたは MZFormSheetController のこのような使用することができます:
MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithSize:customSize viewController:presentedViewController];
formSheet.shouldDismissOnBackgroundViewTap = YES;
[presentingViewController mz_presentFormSheetController:formSheet animated:YES completionHandler:nil];
でスウィフト2 / Xcodeのバージョン7.2(7C68)次のコードは、私のために働いています。
ご注意:このコードはここで、提示FormSheetまたはページシートのViewController.swiftファイルに配置する必要があります:「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)
}
}
}
}