ios - que - mi ipad no gira la pantalla
¿Cómo obtener la altura y el ancho de la pantalla dependientes de la orientación? (10)
Estoy tratando de determinar programáticamente el alto y ancho actual de mi aplicación. Yo uso esto:
CGRect screenRect = [[UIScreen mainScreen] bounds];
Pero esto produce un ancho de 320 y una altura de 480, independientemente de si el dispositivo está en orientación vertical u horizontal. ¿Cómo puedo determinar el ancho y la altura actuales (es decir, dependiendo de la orientación del dispositivo) de mi pantalla principal?
A partir de iOS 8, los límites de la pantalla ahora se devuelven correctos para la orientación actual. Esto significa que un iPad en orientación horizontal [UIScreen mainScreen] .bounds devolvería 768 en iOS <= 7 y 1024 en iOS 8.
Lo siguiente devuelve la altura y el ancho correctos en todas las versiones publicadas.
-(CGRect)currentScreenBoundsDependOnOrientation
{
NSString *reqSysVer = @"8.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
return [UIScreen mainScreen].bounds;
CGRect screenBounds = [UIScreen mainScreen].bounds ;
CGFloat width = CGRectGetWidth(screenBounds) ;
CGFloat height = CGRectGetHeight(screenBounds) ;
UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
screenBounds.size = CGSizeMake(width, height);
NSLog(@"Portrait Height: %f", screenBounds.size.height);
}else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
screenBounds.size = CGSizeMake(height, width);
NSLog(@"Landscape Height: %f", screenBounds.size.height);
}
return screenBounds ;
}
Aquí hay una forma rápida de obtener tamaños de pantalla que dependen de la orientación:
var screenWidth: CGFloat {
if UIInterfaceOrientationIsPortrait(screenOrientation) {
return UIScreen.mainScreen().bounds.size.width
} else {
return UIScreen.mainScreen().bounds.size.height
}
}
var screenHeight: CGFloat {
if UIInterfaceOrientationIsPortrait(screenOrientation) {
return UIScreen.mainScreen().bounds.size.height
} else {
return UIScreen.mainScreen().bounds.size.width
}
}
var screenOrientation: UIInterfaceOrientation {
return UIApplication.sharedApplication().statusBarOrientation
}
Estos se incluyen como una función estándar en un proyecto mío:
Aquí hay una macro útil:
#define SCREEN_WIDTH (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height)
#define SCREEN_HEIGHT (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width)
En iOS 8+ debes usar el método viewWillTransitionToSize:withTransitionCoordinator
:
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// You can store size in an instance variable for later
currentSize = size;
// This is basically an animation block
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Get the new orientation if you want
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
// Adjust your views
[self.myView setFrame:CGRectMake(0, 0, size.width, size.height)];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Anything else you need to do at the end
}];
}
Esto reemplaza el método de animación obsoleto que no dio información sobre el tamaño:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
Escribí categoría para UIScreen
, que funciona en todas las versiones de iOS, para que pueda usarlo así:
[[UIScreen mainScreen] currentScreenSize]
.
@implementation UIScreen (ScreenSize)
- (CGSize)currentScreenSize {
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBounds.size;
if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if ( UIInterfaceOrientationIsLandscape(interfaceOrientation) ) {
screenSize = CGSizeMake(screenSize.height, screenSize.width);
}
}
return screenSize;
}
@end
Este es mi código de solución. Este método puede agregar Categroy de la clase NSObject, o puede definir una clase UIViewController superior personalizada y dejar que todos sus otros UIViewControllers la hereden.
-(CGRect)currentScreenBoundsDependOnOrientation
{
CGRect screenBounds = [UIScreen mainScreen].bounds ;
CGFloat width = CGRectGetWidth(screenBounds) ;
CGFloat height = CGRectGetHeight(screenBounds) ;
UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
screenBounds.size = CGSizeMake(width, height);
}else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
screenBounds.size = CGSizeMake(height, width);
}
return screenBounds ;
}
Tenga en cuenta , después de IOS8, como dice el documento de Apple de la propiedad de límites de UIScreen :
Discusión
Este rectángulo se especifica en el espacio de coordenadas actual, que tiene en cuenta las rotaciones de interfaz vigentes para el dispositivo. Por lo tanto, el valor de esta propiedad puede cambiar cuando el dispositivo gira entre orientaciones vertical y horizontal.
entonces para la consideración de la compatibilidad, debemos detectar la versión de IOS y hacer el cambio de la siguiente manera:
#define IsIOS8 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)
-(CGRect)currentScreenBoundsDependOnOrientation
{
CGRect screenBounds = [UIScreen mainScreen].bounds ;
if(IsIOS8){
return screenBounds ;
}
CGFloat width = CGRectGetWidth(screenBounds) ;
CGFloat height = CGRectGetHeight(screenBounds) ;
UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
screenBounds.size = CGSizeMake(width, height);
}else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
screenBounds.size = CGSizeMake(height, width);
}
return screenBounds ;
}
Puede usar algo como UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)
para determinar la orientación y luego usar las dimensiones correspondientes.
SIN EMBARGO, durante un cambio de orientación como en UIViewController''s
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
Utilice la orientación que se toInterfaceOrientation
a toInterfaceOrientation
ya que la orientación de estadoBarOrication de UIA seguirá apuntando a la orientación anterior ya que aún no ha cambiado (ya que se encuentra dentro de un controlador de eventos de will
).
Resumen
Hay varias publicaciones relacionadas con esto, pero cada una de ellas parece indicar que debes:
- Mire los
[[UIScreen mainScreen] bounds]
para obtener las dimensiones, - Verifique en qué orientación se encuentra, y
- Cuenta para la altura de la barra de estado (si se muestra)
Campo de golf
- Iphone: Obtenga dimensiones de vista o dimensiones de pantalla actuales
- IPhone / IPad: ¿Cómo obtener ancho de pantalla mediante programación?
- Objetivo C: ¿cómo obtener la resolución de pantalla actual?
- Tamaño de marco / ventana "incorrecto" después de la reorientación en iPhone o iPad
- iPhone Dev SDK: obtenga ancho de pantalla
Código de trabajo
Normalmente no voy tan lejos, pero despiertas mi interés. El siguiente código debería hacer el truco. Escribí una Categoría sobre UIApplication. Añadí métodos de clase para obtener el tamaño actual o el tamaño en una orientación determinada, que es lo que llamarías en willRotateToInterfaceOrientation de willRotateToInterfaceOrientation:duration:
@interface UIApplication (AppDimensions)
+(CGSize) currentSize;
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation;
@end
@implementation UIApplication (AppDimensions)
+(CGSize) currentSize
{
return [UIApplication sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
}
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *application = [UIApplication sharedApplication];
if (UIInterfaceOrientationIsLandscape(orientation))
{
size = CGSizeMake(size.height, size.width);
}
if (application.statusBarHidden == NO)
{
size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
}
return size;
}
@end
Para usar el código simple, llame [UIApplication currentSize]
. Además, ejecuté el código anterior, así que sé que funciona e informa las respuestas correctas en todas las orientaciones. Tenga en cuenta que factorizo la barra de estado. Curiosamente tuve que restar el MIN de la altura y el ancho de la barra de estado.
Espero que esto ayude. :RE
Otros pensamientos
Puede obtener las dimensiones mirando la propiedad rootViewController de rootViewController
. He visto esto en el pasado e informa de manera similar las mismas dimensiones tanto en retrato como en paisaje, excepto que informa que tiene una transformación de rotación:
(gdb) po [[[UIApplication sharedApplication] keyWindow] rootViewController] ver]
<UILayoutContainerView: 0xf7296f0; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; Autoresize = W + H; layer = <CALayer: 0xf729b80 >>
(gdb) po [[[UIApplication sharedApplication] keyWindow] rootViewController] ver]
<UILayoutContainerView: 0xf7296f0; frame = (0 0; 320 480); Autoresize = W + H; layer = <CALayer: 0xf729b80 >>
No estoy seguro de cómo funciona su aplicación, pero si no está usando un controlador de navegación de algún tipo, podría tener una UIView debajo de su vista principal con el alto / ancho máximo de uno de los padres y crecer / contraerse con el elemento primario. Entonces podría hacer: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]
. Eso parece bastante intenso en una línea, pero entiendes la idea.
Sin embargo ... Sería mejor hacer los 3 pasos anteriores en el resumen. Comience a jugar con UIWindows y encontrará cosas raras, como mostrar un UIAlertView que cambiará la ventana de claves de UIApplication para apuntar a una nueva UIWindow que creó el UIAlertView. ¿Quien sabe? Lo hice después de encontrar un error confiando en keyWindow y descubriendo que ¡cambió así!
Sin embargo, en iOS 8.0.2:
+ (NSUInteger)currentWindowWidth
{
NSInteger width = 0;
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
CGSize size = [UIScreen mainScreen].bounds.size;
// if (UIInterfaceOrientationIsLandscape(orientation)) {
// width = size.height;
// } else {
width = size.width;
// }
return width;
}
si desea el tamaño dependiente de la orientación y tiene una vista, puede simplemente usar:
view.bounds.size
float msWidth = [[UIScreen mainScreen] bounds].size.width*(IS_RETINA?2.0f:1.0f);
float msHeight = [[UIScreen mainScreen] bounds].size.height*(IS_RETINA?2.0f:1.0f);
if ( UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ) {
os->setWidth(MIN(msWidth, msHeight));
os->setHeight(MAX(msWidth, msHeight));
} else {
os->setWidth(MAX(msWidth, msHeight));
os->setHeight(MIN(msWidth, msHeight));
}
NSLog(@"screen_w %f", os->getWidth());
NSLog(@"screen_h %f", os->getHeight());