Iphone SDK驳回模式ViewControllers果通过点击外
-
26-09-2019 - |
题
我要解雇FormSheetPresentation模式图控制当用户水龙头的外部模式的看...我已经看到了一堆应用程序这样做(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
不能排除这种方式。 (也确实可以在任何UIModal在SDK3.2)。只有UIPopoverController
可以通过点击区域外被解雇。这是非常可能的(虽然对苹果的iPad HIG)为应用开发者已经走出阴影的背景画面,然后显示在UIPopoverController
,使它看起来像一个UIModalPresentationFormSheets
(或其他UIModal视图)。
[...] 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
具有敲击手势识别器,其与最初的实施干涉,所以我们忽略它,并且不要求它失败。
这是速度的时代,所以大部分都可能只是复制上面的代码。但是,我从患有强迫症,当涉及到的代码,很遗憾。
下面是一个使用了Danilo坎普斯的答案与类别的一个模块化解决方案。它还解决了如果您通过其他方式解雇你的模式可能会出现一个重要的错误,提到一>
注意:强>的if语句是有,因为我使用的视图控制器,用于iPhone和iPad,并且仅在iPad需要注册/注销
更新:要点已经更新,因为它没有与真棒的 FCOverlay 代码,并没有让手势所呈现的观点得到认可。这些问题是固定的。 使用类别一样简单:
- (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:
如果您有任何其他的方式来关闭您的模态弹出窗口的,不要忘记删除敲击手势识别!
我忘了这一点,并得到了疯狂的崩溃以后,由于抽头识别仍然触发事件。
根据到苹果高,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和导航条。
如果您不需要导航栏只是删除LOCATION2和第二条件在管道后if语句。
@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(当你点击外)
使用它您的视图控制器内。
希望它帮助。
我知道它的晚,但考虑使用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)下面的代码为我工作。
注意:这个代码应放在所呈现的港前赛绩或页表,的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)
}
}
}
}