스토리 보드 팝 오버를 닫는 방법
다음 UIBarButtonItem
과 같이 Xcode Storyboards를 사용하여 팝 오버를 만들었습니다 (코드가 없음).
팝 오버를 표시하면 잘 작동합니다. 그러나 팝업을 표시 한 것을 탭하면 팝 오버가 사라지 도록 할 수 없습니다 UIBarButtonItem
.
버튼을 처음 누르면 (처음) 팝 오버가 나타납니다. 버튼을 다시 누르면 (두 번째) 동일한 팝 오버가 그 위에 나타나므로 이제 두 개의 팝 오버가 생깁니다 (또는 버튼을 계속 누르면 그 이상). iOS 휴먼 인터페이스 지침 에 따르면 팝 오버가 첫 번째 탭에서 나타나고 두 번째 탭에서 사라지도록해야합니다.
한 번에 하나의 팝 오버 만 화면에 표시되는지 확인하십시오. 동시에 두 개 이상의 팝 오버 (또는 팝 오버처럼 보이고 동작하도록 설계된 사용자 정의보기)를 표시해서는 안됩니다. 특히, 하나의 팝 오버가 다른 팝 오버에서 나오는 캐스케이드 또는 계층의 팝 오버를 동시에 표시하지 않아야합니다.
사용자 UIBarButtonItem
가 두 번째 로을 탭할 때 팝 오버를 해제하려면 어떻게해야합니까?
편집 : 이러한 문제는 iOS 7.1 / Xcode 5.1.1에서 수정 된 것으로 보입니다. (아마도 이전에는 모든 버전을 테스트 할 수 없었습니다. 확실히 iOS 7.0 이후 버전을 테스트 한 이후입니다.)에서 팝 오버 segue를 만들 때 UIBarButtonItem
segue는 팝 오버를 다시 탭하면 팝 오버가 오히려 숨겨집니다. 중복을 보여주는 것보다. UIPresentationController
Xcode 6이 iOS 8 용으로 생성 하는 새로운 기반 팝 오버 세그먼트에도 적합합니다.
내 솔루션은 여전히 이전 iOS 버전을 지원하는 사람들에게 역사적인 관심사가 될 수 있으므로 아래에 남겨 두었습니다.
segue의 팝 오버 컨트롤러에 대한 참조를 저장하고을 반복 호출 할 때 새 값으로 설정하기 전에이를 prepareForSegue:sender:
닫으면 피할 수있는 것은 버튼을 반복해서 누를 때 여러 스택 팝 오버 가 발생하는 문제입니다. 여전히 사용할 수 없습니다. HIG가 권장하는 팝 오버를 닫는 버튼 (및 Apple의 앱 등에 표시됨)
하지만 간단한 솔루션을 위해 ARC 제로화 약한 참조를 활용할 수 있습니다.
1 : 버튼에서 Segue
iOS 5부터는에서 segue로이 작업을 수행 UIBarButtonItem
할 수 없지만 iOS 6 이상에서는 가능합니다. (iOS 5에서는 뷰 컨트롤러 자체에서 분리 한 다음 performSegueWithIdentifier:
팝 오버를 확인한 후 버튼의 액션 호출을 받아야합니다 .)
2 : 팝 오버에 대한 참조 사용 -shouldPerformSegue...
@interface ViewController
@property (weak) UIPopoverController *myPopover;
@end
@implementation ViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// if you have multiple segues, check segue.identifier
self.myPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
if (self.myPopover) {
[self.myPopover dismissPopoverAnimated:YES];
return NO;
} else {
return YES;
}
}
@end
3 : 3 단계가 없습니다!
여기서 제로화 약한 참조를 사용하는 것에 대한 좋은 점은 일단 팝 오버 컨트롤러가 해제되면 (프로그래밍 방식으로에서든 shouldPerformSegueWithIdentifier:
, 사용자가 팝 오버 외부의 다른 곳을 탭하여 자동으로)-ivar가 nil
다시 이동 하므로 우리는 다시 초기 상태.
약한 참조를 제로화하지 않으면 다음 작업도 수행해야합니다.
- 에서 해제
myPopover = nil
할 때 설정shouldPerformSegueWithIdentifier:
하고 - 잡기 위해 우리 자신을 팝 오버 컨트롤러의 델리게이트로
popoverControllerDidDismissPopover:
설정하고myPopover = nil
거기 에서도 설정 합니다 (팝 오버가 자동으로 닫힐 때 잡습니다).
나는 여기에 해결책을 발견 https://stackoverflow.com/a/7938513/665396 첫 prepareForSegue에서 : 보낸 사람 : 저장소를 바르 / 속성하여 UIPopoverController에 대한 포인터와 포인터가 후속 호출에서 팝 오버를 기각 할 것을 사용자.
...
@property (nonatomic, weak) UIPopoverController* storePopover;
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender {
if ([segue.identifier isEqualToString:@"My segue"]) {
// setup segue here
[self.storePopover dismissPopoverAnimated:YES];
self.storePopover = ((UIStoryboardPopoverSegue*)segue).popoverController;
...
}
나는 이것을 위해 사용자 정의 segue를 사용했습니다.
1
Storyboard에서 사용할 사용자 지정 segue를 만듭니다.
@implementation CustomPopoverSegue
-(void)perform
{
// "onwer" of popover - it needs to use "strong" reference to retain UIPopoverReference
ToolbarSearchViewController *source = self.sourceViewController;
UIViewController *destination = self.destinationViewController;
// create UIPopoverController
UIPopoverController *popoverController = [[UIPopoverController alloc] initWithContentViewController:destination];
// source is delegate and owner of popover
popoverController.delegate = source;
popoverController.passthroughViews = [NSArray arrayWithObject:source.searchBar];
source.recentSearchesPopoverController = popoverController;
// present popover
[popoverController presentPopoverFromRect:source.searchBar.bounds
inView:source.searchBar
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
@end
2
segue의 소스 / 입력 인 뷰 컨트롤러에서 예를 들어 액션으로 segue를 시작합니다.
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
if(nil == self.recentSearchesPopoverController)
{
NSString *identifier = NSStringFromClass([CustomPopoverSegue class]);
[self performSegueWithIdentifier:identifier sender:self];
}
}
삼
참조는 UIPopoverController를 생성하는 segue에 의해 할당됩니다-팝 오버를 닫을 때
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
if(self.recentSearchesPopoverController)
{
[self.recentSearchesPopoverController dismissPopoverAnimated:YES];
self.recentSearchesPopoverController = nil;
}
}
안부, 피터
ixPopoverBarButtonItem
segue를 트리거하거나 표시되는 팝 오버를 닫는 사용자 지정 을 생성하여 해결했습니다 .
내가하는 일 : 버튼의 동작과 대상을 토글하여 segue를 트리거하거나 현재 표시된 팝 오버를 삭제합니다.
이 솔루션을 찾기 위해 많은 인터넷 검색이 필요했습니다. 액션을 토글하는 아이디어에 대한 크레딧을 받고 싶지 않습니다. 코드를 사용자 지정 버튼에 넣는 것은 내 관점에서 상용구 코드를 최소한으로 유지하려는 접근 방식이었습니다.
스토리 보드에서 BarButtonItem의 클래스를 사용자 지정 클래스에 정의합니다.
그런 다음 segue에서 만든 팝 오버를 prepareForSegue:sender:
메서드의 사용자 지정 단추 구현에 전달합니다 .
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"myPopoverSegue"]) {
UIStoryboardPopoverSegue* popSegue = (UIStoryboardPopoverSegue*)segue;
[(ixPopoverBarButtonItem *)sender showingPopover:popSegue.popoverController];
}
}
Btw ... 팝 오버를 트리거하는 버튼이 두 개 이상 있기 때문에 현재 표시된 팝 오버에 대한 참조를 유지하고 새 팝 오버를 표시 할 때이를 닫아야합니다. 그러나 이것은 귀하의 질문이 아닙니다 ...
사용자 지정 UIBarButtonItem을 구현 한 방법은 다음과 같습니다.
...상호 작용:
@interface ixPopoverBarButtonItem : UIBarButtonItem
- (void) showingPopover: (UIPopoverController *)popoverController;
@end
... 그리고 impl :
#import "ixPopoverBarButtonItem.h"
@interface ixPopoverBarButtonItem ()
@property (strong, nonatomic) UIPopoverController *popoverController;
@property (nonatomic) SEL tempAction;
@property (nonatomic,assign) id tempTarget;
- (void) dismissPopover;
@end
@implementation ixPopoverBarButtonItem
@synthesize popoverController = _popoverController;
@synthesize tempAction = _tempAction;
@synthesize tempTarget = _tempTarget;
-(void)showingPopover:(UIPopoverController *)popoverController {
self.popoverController = popoverController;
self.tempAction = self.action;
self.tempTarget = self.target;
self.action = @selector(dismissPopover);
self.target = self;
}
-(void)dismissPopover {
[self.popoverController dismissPopoverAnimated:YES];
self.action = self.tempAction;
self.target = self.tempTarget;
self.popoverController = nil;
self.tempAction = nil;
self.tempTarget = nil;
}
@end
추신 : 저는 ARC를 처음 사용하기 때문에 여기에서 유출되고 있는지 완전히 확신하지 못합니다. 내가 만약 ...
.NET Framework의 복사본을 보관할 필요없이이 문제를 해결했습니다 UIPopoverController
. 스토리 보드 (Toolbar, BarButtons 등)의 모든 것을 처리하고
- 부울로 팝 오버의 가시성을 처리합니다.
- 대리자가 있는지 확인하고 self로 설정되어 있습니다.
다음은 모든 코드입니다.
ViewController.h
@interface ViewController : UIViewController <UIPopoverControllerDelegate>
@end
ViewController.m
@interface ViewController ()
@property BOOL isPopoverVisible;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.isPopoverVisible = NO;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// add validations here...
self.isPopoverVisible = YES;
[[(UIStoryboardPopoverSegue*)segue popoverController] setDelegate:self];
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
return !self.isPopoverVisible;
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
self.isPopoverVisible = NO;
}
@end
나는 rickster의 대답을 가져 와서 UIViewController에서 파생 된 클래스로 패키지했습니다. 이 솔루션에는 다음이 필요합니다.
- ARC가있는 iOS 6 이상
- 이 클래스에서 뷰 컨트롤러를 가져옵니다.
- 이러한 메서드를 재정의하는 경우 prepareForSegue : sender 및 shouldPerformSegueWithIdentifier : sender의 "수퍼"버전을 호출해야합니다.
- 명명 된 팝 오버 segue 사용
이것의 좋은 점은 Popover의 적절한 처리를 지원하기 위해 "특별한"코딩을 할 필요가 없다는 것입니다.
인터페이스 :
@interface FLStoryboardViewController : UIViewController
{
__strong NSString *m_segueIdentifier;
__weak UIPopoverController *m_popoverController;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender;
@end
구현 :
@implementation FLStoryboardViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [segue isKindOfClass:[UIStoryboardPopoverSegue class]] )
{
UIStoryboardPopoverSegue *popoverSegue = (id)segue;
if( m_popoverController == nil )
{
assert( popoverSegue.identifier.length > 0 ); // The Popover segue should be named for this to work fully
m_segueIdentifier = popoverSegue.identifier;
m_popoverController = popoverSegue.popoverController;
}
else
{
[m_popoverController dismissPopoverAnimated:YES];
m_segueIdentifier = nil;
m_popoverController = nil;
}
}
else
{
[super prepareForSegue:segue sender:sender];
}
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
// If this is an unnamed segue go ahead and allow it
if( identifier.length != 0 )
{
if( [identifier compare:m_segueIdentifier] == NSOrderedSame )
{
if( m_popoverController == NULL )
{
m_segueIdentifier = nil;
return YES;
}
else
{
[m_popoverController dismissPopoverAnimated:YES];
m_segueIdentifier = nil;
m_popoverController = nil;
return NO;
}
}
}
return [super shouldPerformSegueWithIdentifier:identifier sender:sender];
}
@end
참고 URL : https://stackoverflow.com/questions/8287242/how-to-dismiss-a-storyboard-popover
'developer tip' 카테고리의 다른 글
LaTeX를 UTF8로 컴파일하려면 어떻게해야합니까? (0) | 2020.10.24 |
---|---|
자바 스크립트 (+) 기호는 변수 합계를 제공하는 대신 연결합니다. (0) | 2020.10.24 |
SQL-IF EXISTS UPDATE ELSE INSERT INTO (0) | 2020.10.23 |
ListView 용 Android 사용자 지정 행 항목 (0) | 2020.10.23 |
Crashlytics가 iPhone에서 오류 보고서를 보내지 않음 (0) | 2020.10.23 |