2012-01-30 28 views
19

मैं रोटेशन के बाद स्क्रीन पर पॉपओवर को एक ही स्थिति नहीं रख सकता। ऐसा करने का कोई अच्छा तरीका है, क्योंकि बस कुछ फ्रेम को पॉपओवर पर सेट करना घूर्णन के बाद भयानक काम करता है। popover.frame = CGRectMake(someFrame); रोटेशन पॉपओवर के बाद ही ठीक दिखता है अगर यह स्क्रीन के केंद्र में है।UIPopoverController को घूर्णन के बाद समान स्थिति कैसे बनाए रखें?

+0

इस लिंक पर भी जाँच .. http://stackoverflow.com/ तब प्रतिनिधि विधि को लागू प्रश्न/3670 9 1/समायोजन-uipopovercontroller-position-after-resize –

+0

के लिए धन्यवाद: presentPopoverFromRect: पॉपवॉयर दिखाई देने पर इनव्यू का उपयोग किया जा सकता है –

उत्तर

28

ऐप्पल के पास इस मुद्दे पर एक Q & ए है। आप यहाँ विवरण प्राप्त कर सकते हैं:

Technical Q&A QA1694 Handling Popover Controllers During Orientation Changes

मूल रूप से, तकनीक बताते हैं कि आपके विचार नियंत्रक के didRotateFromInterfaceOrientation विधि में, आप पॉप फिर से इस प्रकार पेश करेंगे:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
{ 
    [aPopover presentPopoverFromRect:targetRect.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 
} 

अधिक जानकारी के लिए उपरोक्त आलेख का एक पठन है, और UIPopoverController Class Reference:

यदि उपयोगकर्ता पॉप-अप होने पर डिवाइस को घुमाता है sible, popover नियंत्रक पॉपओवर को छुपाता है और फिर इसे रोटेशन के अंत में फिर से दिखाता है। पॉपओवर नियंत्रक पॉपओवर को उचित रूप से आपके लिए स्थानांतरित करने का प्रयास करता है लेकिन आपको इसे फिर से पेश करना पड़ सकता है या इसे कुछ मामलों में को पूरी तरह छिपाना पड़ सकता है। उदाहरण के लिए, जब बार बटन आइटम से प्रदर्शित होता है, तो पॉपओवर नियंत्रक स्वचालित रूप से (और संभावित रूप से आकार) को पॉपओवर के में बार बटन आइटम की स्थिति में परिवर्तन के लिए समायोजित करता है। हालांकि, यदि आप रोटेशन के दौरान बार बटन आइटम को हटाते हैं, या यदि आपने पॉपओवर को से एक दृश्य आयताकार में प्रस्तुत किया है, तो पॉपओवर नियंत्रक पॉपओवर को पुनर्स्थापित करने के लिए का प्रयास नहीं करता है। उन मामलों में, आपको पॉपओवर मैन्युअल रूप से छिपाना होगा या इसे एक उचित नई स्थिति से फिर से प्रस्तुत करना होगा। आप कर सकते हैं didRotateFromInterfaceOrientation में: नियंत्रक की विधि जिसे आपने पॉपओवर प्रस्तुत करने के लिए उपयोग किया था।

5

आप इसे पॉप नियंत्रक प्रस्तुत करने के लिए उपयोग किए गए दृश्य नियंत्रक के didRotateFromInterfaceOrientation: विधि में कर सकते हैं।

पॉपओवर के आकार को सेट करने के लिए setPopoverContentSize:animated: विधि का उपयोग करें।

+4

क्या यह विधि पॉपओवर मूल को बदलती है? मुझे मूल रखने के लिए, पॉपओवर सामग्री के आकार को बदलने की आवश्यकता नहीं है। –

1

मैं इसी तरह की समस्या है जो मैं इस

[myPop presentPopoverFromRect:myfield.frame inView:myscrollview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 

कहाँ myfield फ्रेम, जिनसे आप अपने पॉपओवर और myscrollview दिखाना चाहते है द्वारा हल कंटेनर दृश्य है जिसमें आप subview के रूप अपने पॉपओवर जोड़ने (मेरे मामले में है इसके मेरा स्क्रॉलव्यू, inView:self.view डालने के बजाय मैं inView:myscrollview का उपयोग करता हूं)।

0

मुझे एक ही समस्या थी। स्रोत आयताकार/दृश्य को ट्रैक करके प्रत्येक बार -presentPopoverFromRect प्रदर्शन करने के बजाय, मैंने UIPopoverController को उपclassed। ऐसा करने के बाद, आपको बस इतना करना है कि पॉपबार को प्रदर्शित करने के लिए UIBarButtonItem/UIView सेट करें। आप कस्टम फ्रेम से पॉपओवर प्रदर्शित करने का भी चयन कर सकते हैं जिसे एनएसएसटींग मान के रूप में पारित किया जा सकता है।

सीएसपीओवर कंट्रोलर।ज:

#import <UIKit/UIKit.h> 

// The original popover controller would not re-orientate itself when the orientation change occurs. To tackle that issue, this subclass is created 
@interface CSPopoverController : UIPopoverController 

@property (nonatomic, strong) NSString *popoverDisplaySourceFrame; // Mutually Exclusive. If you want to set custom rect as source, make sure that popOverDisplaySource is nil 
@property (nonatomic, strong) id popoverDisplaySource;    // Mutually exclusive. If UIBarButtonItem is set to it, popoverDisplaySourceFrame is neglected. 
@property (nonatomic, strong) UIView *popoverDisplayView; 

@property (nonatomic, assign, getter = shouldAutomaticallyReorientate) BOOL automaticallyReorientate; 

-(void)reorientatePopover; 

@end 

CSPopoverController.m:

#import "CSPopoverController.h" 

@implementation CSPopoverController 
@synthesize popoverDisplaySourceFrame = popoverDisplaySourceFrame_; 
-(NSString*)popoverDisplaySourceFrame 
{ 
    if (nil==popoverDisplaySourceFrame_) 
    { 
     if (nil!=self.popoverDisplaySource) 
     { 
      if ([self.popoverDisplaySource isKindOfClass:[UIView class]]) 
      { 
       UIView *viewSource = (UIView*)self.popoverDisplaySource; 
       [self setPopoverDisplaySourceFrame:NSStringFromCGRect(viewSource.frame)]; 
      } 
     } 
    } 
    return popoverDisplaySourceFrame_; 
} 
-(void)setPopoverDisplaySourceFrame:(NSString *)inPopoverDisplaySourceFrame 
{ 
    if (inPopoverDisplaySourceFrame!=popoverDisplaySourceFrame_) 
    { 
     popoverDisplaySourceFrame_ = inPopoverDisplaySourceFrame; 
     [self reorientatePopover]; 
    } 
} 
@synthesize popoverDisplaySource = popoverDisplaySource_; 
-(void)setPopoverDisplaySource:(id)inPopoverDisplaySource 
{ 
    if (inPopoverDisplaySource!=popoverDisplaySource_) 
    { 
     [self unlistenForFrameChangeInView:popoverDisplaySource_]; 
     popoverDisplaySource_ = inPopoverDisplaySource; 
     [self reorientatePopover]; 

     if ([popoverDisplaySource_ isKindOfClass:[UIView class]]) 
     { 
      UIView *viewSource = (UIView*)popoverDisplaySource_; 
      [self setPopoverDisplaySourceFrame:NSStringFromCGRect(viewSource.frame)]; 
     } 
     if (self.shouldAutomaticallyReorientate) 
     { 
      [self listenForFrameChangeInView:popoverDisplaySource_]; 
     } 
    } 
} 
@synthesize popoverDisplayView = popoverDisplayView_; 
-(void)setPopoverDisplayView:(UIView *)inPopoverDisplayView 
{ 
    if (inPopoverDisplayView!=popoverDisplayView_) 
    { 
     popoverDisplayView_ = inPopoverDisplayView; 
     [self reorientatePopover]; 
    } 
} 
@synthesize automaticallyReorientate = automaticallyReorientate_; 
-(void)setAutomaticallyReorientate:(BOOL)inAutomaticallyReorientate 
{ 
    if (inAutomaticallyReorientate!=automaticallyReorientate_) 
    { 
     automaticallyReorientate_ = inAutomaticallyReorientate; 
     if (automaticallyReorientate_) 
     { 
      [self listenForAutorotation]; 
      [self listenForFrameChangeInView:self.popoverDisplaySource]; 
     } 
     else 
     { 
      [self unlistenForAutorotation]; 
      [self unlistenForFrameChangeInView:self.popoverDisplaySource]; 
     } 
    } 
} 

-(void)listenForAutorotation 
{ 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(orientationChanged:) 
               name:UIDeviceOrientationDidChangeNotification 
               object:nil]; 
} 

-(void)unlistenForAutorotation 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self 
                name:UIDeviceOrientationDidChangeNotification 
                object:nil]; 
} 

-(void)listenForFrameChangeInView:(id)inView 
{ 
    // Let's listen for changes in the view's frame and adjust the popover even if the frame is updated 
    if ([inView isKindOfClass:[UIView class]]) 
    { 
     UIView *viewToObserve = (UIView*)inView; 
     [viewToObserve addObserver:self 
         forKeyPath:@"frame" 
          options:NSKeyValueObservingOptionNew 
          context:nil]; 
    } 
} 

-(void)unlistenForFrameChangeInView:(id)inView 
{ 
    if ([inView isKindOfClass:[UIView class]]) 
    { 
     UIView *viewToObserve = (UIView*)inView; 
     [viewToObserve removeObserver:self 
          forKeyPath:@"frame"]; 
    } 
} 

// TODO: Dealloc is not called, check why? !!! 
- (void)dealloc 
{ 
    [self unlistenForFrameChangeInView:self.popoverDisplaySource]; 
    [self unlistenForAutorotation]; 
    DEBUGLog(@"dealloc called for CSPopoverController %@", self); 
} 

#pragma mark - Designated initializers 
-(id)initWithContentViewController:(UIViewController *)viewController 
{ 
    self = [super initWithContentViewController:viewController]; 
    if (self) 
    { 
     [self popoverCommonInitializations]; 
    } 
    return self; 
} 

-(void)popoverCommonInitializations 
{ 
    [self setAutomaticallyReorientate:YES]; 
} 

#pragma mark - Frame 
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if (object==self.popoverDisplaySource) 
    { 
     [self setPopoverDisplaySourceFrame:nil]; 
     [self reorientatePopover]; 
    } 
} 

#pragma mark - Orientation 
-(void)orientationChanged:(NSNotification *)inNotification 
{ 
    [self reorientatePopover]; 
} 

-(void)reorientatePopover 
{ 
    [NSObject cancelPreviousPerformRequestsWithTarget:self 
              selector:@selector(performReorientatePopover) 
               object:nil]; 
// if ([self isPopoverVisible]) 
    { 
     [self performSelector:@selector(performReorientatePopover) 
        withObject:nil 
        afterDelay:0.0]; 
    } 
} 

-(void)performReorientatePopover 
{ 
    if (self.popoverDisplaySourceFrame && self.popoverDisplayView) 
    { 
     [self presentPopoverFromRect:CGRectFromString(self.popoverDisplaySourceFrame) 
           inView:self.popoverDisplayView 
      permittedArrowDirections:UIPopoverArrowDirectionAny 
          animated:YES]; 
    } 
    else if (self.popoverDisplaySource && [self.popoverDisplaySource isKindOfClass:[UIBarButtonItem class]]) 
    { 
     UIBarButtonItem *barButton = (UIBarButtonItem*)self.popoverDisplaySource; 
     [self presentPopoverFromBarButtonItem:barButton 
        permittedArrowDirections:UIPopoverArrowDirectionAny 
            animated:YES]; 
    } 
} 

@end 

उपयोग:

यदि यह जहां आप इसे प्रस्तुत कर रहे हैं से एक UIBarButtonItem है:

CSPopoverController *popOverCont = [[CSPopoverController alloc]initWithContentViewController:navCont]; 
self.popOver = popOverCont; 
[popOverCont setPopoverDisplaySource:self.settingsButtonItem]; 

यदि यह जहां पॉपओवर प्रस्तुत कर रहे हैं से एक UIView है:

CSPopoverController *popOver = [[CSPopoverController alloc] initWithContentViewController:navigation]; 
self.iPadPopoverController = popOver; 
[newDateVC setIPadPopoverController:self.iPadPopoverController]; 
[popOver setPopoverDisplaySource:inButton]; 
[popOver setPopoverDisplayView:inView]; 
6

iOS 7 में आप - (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view उपयोग कर सकते हैं इंटरफ़ेस उन्मुखीकरण परिवर्तन पर अपने UIPopoverController का नजरिया बदलने के लिए।

UIPopoverControllerDelegatedocumentation देखें।

+0

धन्यवाद, यह मेरे लिए आईओएस 8 – almas

15

आईओएस के रूप में 8.0.2 willRotateToInterfaceOrientation का कोई प्रभाव नहीं होगा

- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view 
{ 
    CGRect rectInView = [self.theButton convertRect:self.theButton.frame toView:self.view]; 
    *rect = CGRectMake(CGRectGetMidX(rectInView), CGRectGetMaxY(rectInView), 1, 1); 
    *view = self.view; 
} 
:

- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view

इसलिए उदाहरण के लिए यदि आप अपने पॉपओवर सीधे कि एक बटन दबाया गया था नीचे प्रकट करने के लिए आप निम्न कोड का प्रयोग करेंगे चाहते हैं, तो: mhrrt उल्लेख किया है, आप प्रतिनिधि विधि का उपयोग करने की आवश्यकता है

0

आईओएस के लिए> 8 जॉन स्ट्राइकर्स ने जवाब दिया लेकिन ऐसा नहीं किया जो मैं करना चाहता था।

यहां समाधान है जो मेरे लिए काम करता है। (यदि आप एक पूर्ण नमूना प्रोजेक्ट डाउनलोड करना चाहते हैं तो यह यहां है: https://github.com/appteur/uipopoverExample)

मैंने किसी भी पॉपओवर को रखने के लिए एक संपत्ति बनाई है जिसे मैं प्रस्तुत करना चाहता था और बटन को देखने के लिए स्रोत और अन्य ट्रैक को ट्रैक करने के लिए एक संपत्ति भी जोड़ा पॉइंट ओवर तीर पर इंगित करने के लिए।

@property (nonatomic, weak) UIView *activePopoverBtn; 
@property (nonatomic, strong) PopoverViewController *popoverVC; 
@property (nonatomic, assign) CGRect sourceRect; 

मेरे पॉपओवर को ट्रिगर करने वाला बटन UIToolbar में है। जब टैप किया जाता है तो यह निम्न विधि चलाता है जो पॉपओवर बनाता है और लॉन्च करता है।

-(void) buttonAction:(id)sender event:(UIEvent*)event 
{ 
    NSLog(@"ButtonAction"); 

    // when the button is tapped we want to display a popover, so setup all the variables needed and present it here 

    // get a reference to which button's view was tapped (this is to get 
    // the frame to update the arrow to later on rotation) 
    // since UIBarButtonItems don't have a 'frame' property I found this way is easy 
    UIView *buttonView   = [[event.allTouches anyObject] view]; 

    // set our tracker properties for when the orientation changes (handled in the viewWillTransitionToSize method above) 
    self.activePopoverBtn  = buttonView; 
    self.sourceRect    = buttonView.frame; 

    // get our size, make it adapt based on our view bounds 
    CGSize viewSize    = self.view.bounds.size; 
    CGSize contentSize   = CGSizeMake(viewSize.width, viewSize.height - 100.0); 

    // set our popover view controller property 
    self.popoverVC = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"PopoverVC"]; 

    // configure using a convenience method (if you have multiple popovers this makes it faster with less code) 
    [self setupPopover:self.popoverVC 
     withSourceView:buttonView.superview // this will be the toolbar 
      sourceRect:self.sourceRect 
      contentSize:contentSize]; 

    [self presentViewController:self.popoverVC animated:YES completion:nil]; 

} 

'setupPopover: withSourceView: sourceRect: contentSize विधि बस यदि आप कई R आर प्रदर्शित करने के लिए योजना बनाने और उन्हें एक ही कॉन्फ़िगर किया गया चाहते popoverPresentationController गुणों को सेट करने के लिए एक सुविधा विधि है। यह कार्यान्वयन नीचे है।

// convenience method in case you want to display multiple popovers 
-(void) setupPopover:(UIViewController*)popover withSourceView:(UIView*)sourceView sourceRect:(CGRect)sourceRect contentSize:(CGSize)contentSize 
{ 
    NSLog(@"\npopoverPresentationController: %@\n", popover.popoverPresentationController); 

    popover.modalPresentationStyle = UIModalPresentationPopover; 
    popover.popoverPresentationController.delegate = self; 
    popover.popoverPresentationController.sourceView    = sourceView; 
    popover.popoverPresentationController.sourceRect    = sourceRect; 
    popover.preferredContentSize         = contentSize; 
    popover.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionDown; 
    popover.popoverPresentationController.backgroundColor   = [UIColor whiteColor]; 
} 

iOS 8 के लिए और ऊपर viewWillTransitionToSize: withTransitionCoordinator प्राप्त दृश्य नियंत्रक जब डिवाइस घूमता है पर कहा जाता है।

मैंने नीचे दिखाए गए अनुसार मेरे प्रस्तुत दृश्य नियंत्रक वर्ग में इस विधि को लागू किया।

// called when rotating a device 
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator 
{ 
    NSLog(@"viewWillTransitionToSize [%@]", NSStringFromCGSize(size)); 

    // resizes popover to new size and arrow location on orientation change 
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) 
    { 
     if (self.popoverVC) 
     { 
      // get the new frame of our button (this is our new source rect) 
      CGRect viewframe = self.activePopoverBtn ? self.activePopoverBtn.frame : CGRectZero; 

      // update our popover view controller's sourceRect so the arrow will be pointed in the right place 
      self.popoverVC.popoverPresentationController.sourceRect = viewframe; 

      // update the preferred content size if we want to adapt the size of the popover to fit the new bounds 
      self.popoverVC.preferredContentSize = CGSizeMake(self.view.bounds.size.width -20, self.view.bounds.size.height - 100); 
     } 

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { 
     // anything you want to do when the transition completes 
    }]; 
} 
1

मैंने केवल नए रेक्ट (rect.initialize (...)) को सेट करने का प्रयास किया है और यह काम करता है।

func popoverPresentationController(popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverToRect rect: UnsafeMutablePointer<CGRect>, inView view: AutoreleasingUnsafeMutablePointer<UIView?>) { 

     if popoverPresentationController.presentedViewController.view.tag == Globals.PopoverTempTag 
     { 
      rect.initialize(getForPopupSourceRect()) 
     } 
    } 
0

UIPopoverControllerUIPopoverPresentationController के पक्ष iOS8 में शुरू में ios9 में पदावनत किया गया था। (मैं इस संक्रमण के माध्यम से भी चला गया जब UIActionSheet से UIAlertController के लिए जा रहा।) आपके पास दो विकल्प (Obj सी में उदाहरण) है:

ए को लागू करें नीचे UIViewController विधि (UIKit एक प्रस्तुत के आकार बदलने से पहले इस प्रणाली को बुलाती है नियंत्रक के विचार देखें)।

- (void)viewWillTransitionToSize:(CGSize)size 
      withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { 
     [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; 
     [coordinator animateAlongsideTransition:nil 
            completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { 
             // Fix up popover placement if necessary, *after* the transition. 
             // Be careful here if a subclass also overrides this method. 
             if (self.presentedViewController) { 
              UIPopoverPresentationController *presentationController = 
                [self.presentedViewController popoverPresentationController]; 
              UIView *selectedView = /** YOUR VIEW */; 
              presentationController.sourceView = selectedView.superview; 
              presentationController.sourceRect = selectedView.frame; 
             } 
            }]; 
    } 

बी वैकल्पिक रूप से, जब अपने UIPopoverPresentationController पेश करने के लिए कॉन्फ़िगर करना, भी अपने प्रतिनिधि निर्धारित किया है। जैसे आपका प्रस्तुतिकरण वीसी UIPopoverPresentationControllerDelegate लागू कर सकता है और खुद को प्रतिनिधि के रूप में असाइन कर सकता है।

- (void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController 
      willRepositionPopoverToRect:(inout CGRect *)rect 
           inView:(inout UIView * _Nonnull *)view { 
    UIView *selectedView = /** YOUR VIEW */; 
    // Update where the arrow pops out of in the view you selected. 
    *view = selectedView; 
    *rect = selectedView.bounds; 
} 
0

स्विफ्ट 3::

class MyClass: UIViewController, UIPopoverPresentationControllerDelegate { 


     ... 

     var popover:UIPopoverPresentationController? 

     ... 

     // Where you want to set the popover... 
     popover = YourViewController?.popoverPresentationController 
     popover?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) 
     popover?.delegate = self 

     ... 

     // override didRotate... 
     override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { 
      popover?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) 
     } 

} 
+0

'didRotate' पर [बहिष्कृत] है [https://developer.apple.com/documentation/uikit/uiviewcontroller/1621492-didrotate)। आपको https://stackoverflow.com/a/41561021/954643 में उल्लिखित दो दृष्टिकोणों में से एक का उपयोग करना चाहिए, उदा। 'popoverPresentationController (_: willRepositionPopoverTo: in:) '([docs] (https://developer.apple.com/documentation/uikit/uipopoverpresentationcontrollerdelegate/1622326-popoverpresentationcontroller?preferredLanguage=swift)) यह एक भाग में है क्योंकि आप इसे बदल सकते हैं अब रोटेशन से अधिक स्क्रीन द्वारा लेआउट, जैसे ios9 + में स्प्लिट-स्क्रीन मल्टीटास्किंग सुविधाओं के माध्यम से – qix

0

स्विफ्ट के लिए:

func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) 
{ 
    rect.pointee = CGRect(x: self.view.frame.size.width, y: 0, width: 1, height: 1) // Set new rect here 
}