Iphone SDK는 외부를 클릭하여 ipad에서 Modal ViewController를 닫습니다.
사용자가 모달보기 외부를 탭할 때 FormSheetPresentation 모달보기 컨트롤러를 닫고 싶습니다 ...이 작업을 수행하는 앱 (예 : ipad의 이베이)을 보았지만 아래보기가 터치에서 비활성화 되었기 때문에 방법을 알 수 없습니다. 모달 뷰가 이와 같이 표시 될 때 (아마도 팝 오버로 표시됩니까?) ... 누구나 제안 사항이 있습니까?
나는 1 년 늦었지만 이것은 매우 간단합니다.
모달 뷰 컨트롤러가 뷰의 창에 제스처 인식기를 연결하도록합니다.
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
영역 외부를 클릭하면의 만 해제 할 수 있습니다. 앱 개발자가 배경 화면을 음영 처리 한 다음 (또는 다른 UIModal 뷰) UIPopoverController
처럼 보이도록 표시하는 것은 매우 가능합니다 (애플의 iPad HIG에 대해 UIModalPresentationFormSheets
).
[...] 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의 답변을 범주로 사용하는 모듈 식 솔루션입니다 . 또한 언급했듯이 다른 방법을 통해 모달을 해제 할 때 발생할 수있는 중요한 버그를 해결 합니다 .
참고 : iPhone과 iPad 모두에 뷰 컨트롤러를 사용하고 iPad 만 등록 / 등록 취소하면되기 때문에 if 문이 있습니다.
업데이트 : 멋진 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:
모달 팝업 창 을 닫는 다른 방법이있는 경우 탭 제스처 인식기를 제거하는 것을 잊지 마십시오!
나는 이것을 잊어 버렸고 나중에 탭 인식기가 여전히 이벤트를 발생시키고 있었기 때문에 미친 충돌이 발생했습니다.
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>
set yourself as the delegate for the recognizer:
self.recognizer.delegate = self;
and implement this delegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
It is pretty doable.
Take a look here
https://stackoverflow.com/a/26016458/4074557
It is a NavigationController (modal) that auto dismiss for ipad (when you tap outside)
Use your viewcontroller inside of it.
Hope it helps.
I know it's late but consider using CleanModal (tested with iOS 7 and 8).
https://github.com/orafaelreis/CleanModal
You can use MZFormSheetController like this:
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) the following code worked for me.
Attention: this code should be put in the ViewController.swift file of the presented FormSheet or Page Sheet, here: "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)
}
}
}
}
ReferenceURL : https://stackoverflow.com/questions/2623417/iphone-sdk-dismissing-modal-viewcontrollers-on-ipad-by-clicking-outside-of-it
'programing' 카테고리의 다른 글
node.js에서 전역 변수를 사용하는 방법은 무엇입니까? (0) | 2021.01.16 |
---|---|
JavaScript에서 MD5 파일 해시를 생성하는 방법은 무엇입니까? (0) | 2021.01.16 |
두 NSDate 객체의 차이점 — 결과도 NSDate (0) | 2021.01.16 |
오전 / 오후 형식으로 시간을 얻는 방법 iphone NSDateFormatter? (0) | 2021.01.16 |
Swift에서 두 버전 문자열 비교 (0) | 2021.01.16 |