No puedo mantener Popover en la misma posición en la pantalla después de la rotación. ¿Hay alguna buena manera de hacerlo, porque simplemente establecer un marco para popover funciona terrible después de la rotación. popover.frame = CGRectMake(someFrame);
Después del popover de rotación se ve bien solo si está en el centro de la pantalla.¿Cómo hacer que UIPopoverController mantenga la misma posición después de rotar?
Respuesta
Apple tiene un Q & A sobre exactamente este problema. Puede encontrar los detalles aquí:
Technical Q&A QA1694 Handling Popover Controllers During Orientation Changes
Básicamente, la técnica explica que en el método de su controlador de vista didRotateFromInterfaceOrientation
, se le presentará el estallido de nuevo de la siguiente manera:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[aPopover presentPopoverFromRect:targetRect.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
Para obtener más información, tener una lectura del artículo anterior, y también el UIPopoverController Class Reference:
Si el usuario gira el dispositivo mientras que un popover es vi sible, el controlador popover oculta la popover y luego muestra de nuevo al final de la rotación . El controlador popover intentos para colocar el popover apropiada para usted, pero puede que tenga que presentar de nuevo o esconderlo por completo en algunos casos. Por ejemplo, cuando se visualiza desde un elemento de botón de barra , el controlador popover ajusta automáticamente la posición (y posiblemente el tamaño) del popover para tener en cuenta los cambios a la posición del elemento del botón de barra. Sin embargo, si elimina la barra elemento de botón durante la rotación, o si presentó el popover de un rectángulo de destino en una vista, el controlador popover no intenta para reposicionar el popover. En esos casos, debe ocultar manualmente el popover o presentarlo nuevamente desde una nueva posición apropiada. Puede hacer esto en el didRotateFromInterfaceOrientation: método de la vista del controlador de que utilizó para presentar el popover.
Puede hacerlo en el método didRotateFromInterfaceOrientation:
del controlador de vista que utilizó para presentar el popover.
Uso setPopoverContentSize:animated:
método para establecer el tamaño de la popover.
¿Este método cambia el origen de popover? No necesito cambiar el tamaño del contenido de popover, solo para mantener el origen. –
que tienen un problema similar que resuelvo por esta
[myPop presentPopoverFromRect:myfield.frame inView:myscrollview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Dónde myfield
es el marco desde el que desea mostrar su popover y myscrollview
es vista recipiente en el que se agrega el popover como subvista (en mi caso su mi scrollview, en lugar de poner inView:self.view
utilizo inView:myscrollview
).
Tuve el mismo problema. En lugar de realizar -presentPopoverFromRect
cada vez siguiendo el rectángulo/vista de origen desde el que se presenta, he subclasificado UIPopoverController
. Después de hacerlo, todo lo que tiene que hacer es configurar UIBarButtonItem/UIView desde donde debe mostrarse el popover. Incluso puede optar por mostrar el popover desde el marco personalizado que se puede pasar como un valor de NSString.
CSPopoverController.h:
#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
Uso:
Si se trata de un UIBarButtonItem desde donde se está presentando es:
CSPopoverController *popOverCont = [[CSPopoverController alloc]initWithContentViewController:navCont];
self.popOver = popOverCont;
[popOverCont setPopoverDisplaySource:self.settingsButtonItem];
Si se trata de un UIView desde donde se está presentando el popover:
CSPopoverController *popOver = [[CSPopoverController alloc] initWithContentViewController:navigation];
self.iPadPopoverController = popOver;
[newDateVC setIPadPopoverController:self.iPadPopoverController];
[popOver setPopoverDisplaySource:inButton];
[popOver setPopoverDisplayView:inView];
En iOS 7 se puede utilizar para volver a colocar - (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view
vista de su UIPopoverController sobre el cambio de orientación de la interfaz.
Ver el UIPopoverControllerDelegate
documentation.
Gracias, esto funcionó para mí en iOS 8 – almas
A partir de iOS 8.0.2 willRotateToInterfaceOrientation no tendrá ningún efecto. Como mhrrt mencionado, es necesario utilizar el método delegado:
- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view
Así por ejemplo, si usted quiere que su popover que aparezca directamente debajo de un botón que se ha pulsado, se utiliza el siguiente código:
- (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;
}
Para iOS> 8 La respuesta de John Strickers ayudó pero no hizo lo que yo quería que hiciera.
Aquí está la solución que funcionó para mí. (Si desea descargar un proyecto de muestra completo aquí: https://github.com/appteur/uipopoverExample)
Creé una propiedad para contener cualquier popover que quisiera presentar y también agregué una propiedad para rastrear el sourceRect y otra para la vista del botón que quería la flecha de popover para apuntar.
@property (nonatomic, weak) UIView *activePopoverBtn;
@property (nonatomic, strong) PopoverViewController *popoverVC;
@property (nonatomic, assign) CGRect sourceRect;
El botón que activó mi popover está en una barra de UIToolbar. Cuando se toca se ejecuta el siguiente método que crea e inicia el popover.
-(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];
}
El 'setupPopover: withSourceView: sourceRect: Método contentSize es simplemente un método de conveniencia para establecer las propiedades popoverPresentationController si va a mostrar varios panecillos y quiere que configuran la misma. Su implementación está abajo.
// 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];
}
Para iOS 8 y hasta el viewWillTransitionToSize: withTransitionCoordinator get se llama en el controlador de vista cuando se gira el dispositivo.
Implementé este método en mi clase de controlador de vista presentadora como se muestra a continuación.
// 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
}];
}
He intentado simplemente establecer un nuevo rect (rect.initialize (...)) y funciona.
func popoverPresentationController(popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverToRect rect: UnsafeMutablePointer<CGRect>, inView view: AutoreleasingUnsafeMutablePointer<UIView?>) {
if popoverPresentationController.presentedViewController.view.tag == Globals.PopoverTempTag
{
rect.initialize(getForPopupSourceRect())
}
}
UIPopoverController
está desfasada y en ios9 a favor de UIPopoverPresentationController introducido en ios8. (Fui a través de esta transición también cuando se va UIActionSheet
-UIAlertController
.) Usted tiene dos opciones (ejemplo de obj-C):
A. implementar el método UIViewController
a continuación (UIKit llama a este método antes de cambiar el tamaño de una presentados ver la vista del controlador).
- (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;
}
}];
}
B. Alternativamente, cuando la configuración de su UIPopoverPresentationController
hasta la actualidad, también se establezca su delegado. p.ej. su presentación vc puede implementar UIPopoverPresentationControllerDelegate
y asignarse a sí mismo como el delegado. A continuación, poner en práctica el método delegado:
- (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;
}
Swift 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)
}
}
'didRotate' está [en desuso] (https://developer.apple.com/documentation/uikit/uiviewcontroller/1621492-didrotate). Debería utilizar uno de los dos enfoques que mencioné en https://stackoverflow.com/a/41561021/954643, p. Ej. 'popoverPresentationController (_: willRepositionPopoverTo: in:)' ([docs] (https://developer.apple.com/documentation/uikit/uipopoverpresentationcontrollerdelegate/1622326-popoverpresentationcontroller?preferredLanguage=swift)) Esto se debe en parte a que puede cambiar el diseño de una pantalla por más de rotaciones ahora, como a través de las funciones de multitarea de pantalla dividida en ios9 + – qix
para SWIFT:
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
}
- 1. Ajustar la posición de UIPopoverController después de cambiar el tamaño
- 2. UIPopoverController, cómo cambiar el tamaño de la misma?
- 3. Presente UIPopoverController en la misma posición con el cambio de desplazamiento de flecha simple
- 4. Después de rotar un CALayer usando CABasicAnimation la capa salta a su posición no girada
- 5. Mantenga la API de pantalla completa en pantalla completa después de hacer clic en un vínculo
- 6. transformar escala después de rotar
- 7. C# WinForms - Mantenga un ContextMenu del cierre después de hacer clic en ciertos elementos
- 8. Jquery animate div a la misma posición que otro div
- 9. UIPopoverController que altera la ubicación de UIPopoverArrowDirection
- 10. ¿Puedo hacer que TComboBoxEx tenga la misma altura que TComboBox?
- 11. Eliminar la sombra interna que crea UIPopoverController
- 12. ¿Cómo asegurar que ese impulso se mantenga después de un hito de desarrollo importante?
- 13. ¿Cómo se reduce la escala de un ImageView con ObjectAnimator, pero que mantenga su posición en el diseño?
- 14. ¿Cómo hacer que WiX deje archivos después de la desinstalación?
- 15. ¿Cómo hacer que NSSearchField envíe acción después de la autocompletación?
- 16. Cómo hacer que mi aplicación se mantenga al tanto de las aplicaciones de pantalla completa
- 17. ¿Cómo hacer que JavaC mantenga buenos archivos de clase cuando fallan algunos archivos de entrada?
- 18. Cómo establecer la posición superior = 0 después de setStatusBarHidden: ¿Sí?
- 19. ¿Cómo rotar la imagen en relación con la posición del mouse?
- 20. Cómo ahorrar posición después de DataGridView recarga
- 21. PHP - hacer que la sesión caduque después de X minutos
- 22. Cómo redirigir a la misma página después de iniciar sesión
- 23. Cómo insertar un elemento después de la posición del iterador
- 24. Cómo hacer que una imagen gire continuamente?
- 25. cómo hacer frente a la posición en la aC# corriente
- 26. google maps estilo uipopovercontroller
- 27. Después de la animación, la posición de vista se restablece
- 28. Cómo hacer que los divs internos flotantes tengan la misma altura que el div más alto
- 29. ¿Cómo puedo hacer que la tecla de inicio me ponga en la posición 1 en Eclipse?
- 30. UIPopoverController personalizado?
simplemente si este enlace también .. http://stackoverflow.com/ preguntas/3670981/adjust-uipopovercontroller-position-after-resize –
Gracias por: presentPopoverFromRect: inView se puede usar cuando popover es visible –