ios6视图控制器不正确的宽度/范围-景观模式

时间:2022-08-05 22:23:28

My app utilizes both landscape mode and portrait mode and the user can switch between the two at will.

我的app同时使用了横向模式和纵向模式,用户可以随意在两者之间切换。

When a view controller is presented by a parent view controller that is in portrait orientation, the opened view controller will have the correct width & frame.

当一个视图控制器由处于纵向的父视图控制器呈现时,打开的视图控制器将具有正确的宽度和帧。

However, if the parent view controller is in landscape mode, then on IOS6 (it works correctly on IOS7), the child view controller will be too large and actually a little too short also when it is presented.

但是,如果父视图控制器处于横向模式,那么在IOS6上(它在IOS7上工作正确),子视图控制器在显示时就会太大,实际上也会太短。

Note this is not because the values are reported incorrectly since [[UIScreen mainScreen] bounds] reports the same values regardless of the orientation the child controller is loaded in.

注意,这并不是因为报告的值不正确,因为[[UIScreen mainScreen] bounds]报告的值与加载子控制器的方向无关。

Any ideas on how to fix this / why this is happening? Any idea on how to force the IOS6 versions to behave like IOS7 is now behaving natively? Many thanks!!!

对于如何解决这个问题/为什么会发生这种情况有什么想法吗?关于如何迫使IOS6版本像IOS7一样运行的想法,现在已经有了吗?多谢! ! !

Edit:: Here's how the vc's are presented:

编辑::以下是vc的呈现方式:

AppDelegate

AppDelegate

Launch1 *launch1 =[[Launch1 alloc] init];
self.window.rootViewController = launcher;
[self.window makeKeyAndVisible];

Launch1 class

Launch1类

Search *search = [[Search alloc] init];
[self presentViewController:search animated:YES completion:nil];

Search class

搜索类

//load list_container
views = [[Search_custom_views alloc] initWithControllerContext:self];
[self.view addSubview:views];

Search_custom_views UIView extension:

Search_custom_views UIView扩展:

- (id)initWithControllerContext:(UIViewController*)contextstart {

    //set size of the screen
    CGRect screenRect = [[UIScreen mainScreen] bounds];

    self = [super initWithFrame:screenRect];

    if (self) {
     ....

2 个解决方案

#1


2  

So this was a tough one. I load all my views programmatically. They basically are UIView subclasses that correspond to each view controller. For some reason, when an IOS6 view controller is opened from a parent view controller in landscape mode, the child view controller's bounds are not immediately passed on the child vc's UIView subclasses (if you just use addSubview in the viewDidLoad method of the controller--it is not enough). IOS7 does not have this problem.

这是一个很难的问题。我以编程方式加载所有视图。它们基本上是对应于每个视图控制器的UIView子类。出于某种原因,当以横向模式从父视图控制器打开IOS6视图控制器时,子视图控制器的边界不会立即传递给子vc的UIView子类(如果您只是在控制器的viewDidLoad方法中使用addSubview—这是不够的)。IOS7没有这个问题。

The fix for IOS6 for me was doing the following in the viewDidLoad method of the child view controller:

对我来说,IOS6的修复是在子视图控制器的viewDidLoad方法中完成的:

//add view subclass to view controller
[self.view addSubview:views];

//reset bounds & refresh layout for IOS6
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
    views.frame = self.view.bounds;
    [views layoutIfNeeded];
}

#2


0  

iOS 7 likes it when you call [[UIScreen mainScreen] bounds] instead of [[UIScreen mainScreen] applicationFrame] because the applicationFrame property is not consistently calculated between different versions of iOS, while bounds is.

iOS 7喜欢调用[UIScreen主屏幕]bounds而不是[[UIScreen主屏幕]applicationFrame],因为在不同版本的iOS中,applicationFrame属性不是一致计算的,而bounds则是。

It should be backwards compatible, so you should be able to do something like this:

它应该是向后兼容的,所以你应该能够做这样的事情:

- (CGRect)filterBankFrameForOrientation:(UIInterfaceOrientation)orientation {
    CGRect appFrame = [[UIScreen mainScreen] bounds];
    if (UIInterfaceOrientationIsLandscape(orientation)) {//using bounds here instead of applicationFrame for iOS7 compatibility
        //Handle landscape orientation
        filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.height, k_filterBankHeight);
    }
    else {
        //Handle portrait orientation
        filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.width, k_filterBankHeight);
    }
    return filterBankFrame;
}

and simply flip the height and width values as needed (since bounds will always be in "portrait" orientation)

只需根据需要翻转高度和宽度值(因为界限总是处于“纵向”方向)

Using bounds should give you the consistency you need for identical behavior across iOS versions and device sizes.

使用边界应该能使您在iOS版本和设备大小上具有相同行为所需的一致性。

Updating in response to OP's updated code

更新响应OP的更新代码。

One approach I'd recommend you at least consider is wiring up these views in InterfaceBuilder and using AutoLayout to worry about the rotations for you. It has the added benefit of gracefully handling ALL of the different screen sizes available too, so that can be nice too.

我建议您至少考虑一种方法,即在InterfaceBuilder中连接这些视图,并使用AutoLayout来为您担心旋转。它还有一个额外的好处,即可以优雅地处理所有可用的不同屏幕大小,所以这也很不错。

Still, creating and managing it all in code is perfectly acceptable too, and may be the right call for your situation. If so, you'll want to override a few of the rotation handling methods of UIViewController. Probably most or all of these:

尽管如此,在代码中创建和管理它也是完全可以接受的,并且可能是您的情况的正确调用。如果是,您将需要重写UIViewController的一些旋转处理方法。可能大部分或全部是:

– shouldAutorotate
– supportedInterfaceOrientations
– preferredInterfaceOrientationForPresentation
– willRotateToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation

at a minimum the first one and the last two.

至少第一个和最后两个。

To avoid being tied to one orientation only at launch, it is a common design pattern (citation needed) to write a method like the one I posted above, and then utilize it from both viewDidLoad as well as from the willRotate / didRotate class methods.

为了避免仅仅在启动时被绑定到一个方向,通常的设计模式(引用需要)是编写一个方法,就像我上面发布的方法一样,然后从viewDidLoad和willRotate / didRotate类方法中使用它。

When calling during viewDidLoad, you do something like this:

当在viewDidLoad调用时,您将执行以下操作:

_filterBank.collectionView.frame = [self filterBankFrameForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];

which uses the statusBarOrientation property to launch correctly in either landscape or portrait.

它使用statusBarOrientation属性在横向和纵向中正确地启动。

The willRotate / didRotate methods both give you a parameter you can pass to your frame generating method.

willRotate / didRotate方法都为您提供了可以传递给框架生成方法的参数。

Your method gives you the right frame size, then it's all up to you to pass down this info and manipulate your view hierarchy accordingly. It's easier than it sounds...

您的方法为您提供了正确的帧大小,然后由您来传递此信息并相应地操作您的视图层次结构。这比听起来容易……

(in your case, it looks like launcher would implement the methods, then coordinate the adjustments to launch1 and then down to search and finally to Search_custom_views)

(在您的示例中,好像launcher将实现这些方法,然后协调对launch1的调整,然后再到search,最后到Search_custom_views)

(**last side note, you'll make more friends here by choosing SearchCustomViews instead of Search_custom_views)

(**最后注意,您将通过选择searchcustomview而不是Search_custom_views来结交更多的朋友)

#1


2  

So this was a tough one. I load all my views programmatically. They basically are UIView subclasses that correspond to each view controller. For some reason, when an IOS6 view controller is opened from a parent view controller in landscape mode, the child view controller's bounds are not immediately passed on the child vc's UIView subclasses (if you just use addSubview in the viewDidLoad method of the controller--it is not enough). IOS7 does not have this problem.

这是一个很难的问题。我以编程方式加载所有视图。它们基本上是对应于每个视图控制器的UIView子类。出于某种原因,当以横向模式从父视图控制器打开IOS6视图控制器时,子视图控制器的边界不会立即传递给子vc的UIView子类(如果您只是在控制器的viewDidLoad方法中使用addSubview—这是不够的)。IOS7没有这个问题。

The fix for IOS6 for me was doing the following in the viewDidLoad method of the child view controller:

对我来说,IOS6的修复是在子视图控制器的viewDidLoad方法中完成的:

//add view subclass to view controller
[self.view addSubview:views];

//reset bounds & refresh layout for IOS6
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
    views.frame = self.view.bounds;
    [views layoutIfNeeded];
}

#2


0  

iOS 7 likes it when you call [[UIScreen mainScreen] bounds] instead of [[UIScreen mainScreen] applicationFrame] because the applicationFrame property is not consistently calculated between different versions of iOS, while bounds is.

iOS 7喜欢调用[UIScreen主屏幕]bounds而不是[[UIScreen主屏幕]applicationFrame],因为在不同版本的iOS中,applicationFrame属性不是一致计算的,而bounds则是。

It should be backwards compatible, so you should be able to do something like this:

它应该是向后兼容的,所以你应该能够做这样的事情:

- (CGRect)filterBankFrameForOrientation:(UIInterfaceOrientation)orientation {
    CGRect appFrame = [[UIScreen mainScreen] bounds];
    if (UIInterfaceOrientationIsLandscape(orientation)) {//using bounds here instead of applicationFrame for iOS7 compatibility
        //Handle landscape orientation
        filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.height, k_filterBankHeight);
    }
    else {
        //Handle portrait orientation
        filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.width, k_filterBankHeight);
    }
    return filterBankFrame;
}

and simply flip the height and width values as needed (since bounds will always be in "portrait" orientation)

只需根据需要翻转高度和宽度值(因为界限总是处于“纵向”方向)

Using bounds should give you the consistency you need for identical behavior across iOS versions and device sizes.

使用边界应该能使您在iOS版本和设备大小上具有相同行为所需的一致性。

Updating in response to OP's updated code

更新响应OP的更新代码。

One approach I'd recommend you at least consider is wiring up these views in InterfaceBuilder and using AutoLayout to worry about the rotations for you. It has the added benefit of gracefully handling ALL of the different screen sizes available too, so that can be nice too.

我建议您至少考虑一种方法,即在InterfaceBuilder中连接这些视图,并使用AutoLayout来为您担心旋转。它还有一个额外的好处,即可以优雅地处理所有可用的不同屏幕大小,所以这也很不错。

Still, creating and managing it all in code is perfectly acceptable too, and may be the right call for your situation. If so, you'll want to override a few of the rotation handling methods of UIViewController. Probably most or all of these:

尽管如此,在代码中创建和管理它也是完全可以接受的,并且可能是您的情况的正确调用。如果是,您将需要重写UIViewController的一些旋转处理方法。可能大部分或全部是:

– shouldAutorotate
– supportedInterfaceOrientations
– preferredInterfaceOrientationForPresentation
– willRotateToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation

at a minimum the first one and the last two.

至少第一个和最后两个。

To avoid being tied to one orientation only at launch, it is a common design pattern (citation needed) to write a method like the one I posted above, and then utilize it from both viewDidLoad as well as from the willRotate / didRotate class methods.

为了避免仅仅在启动时被绑定到一个方向,通常的设计模式(引用需要)是编写一个方法,就像我上面发布的方法一样,然后从viewDidLoad和willRotate / didRotate类方法中使用它。

When calling during viewDidLoad, you do something like this:

当在viewDidLoad调用时,您将执行以下操作:

_filterBank.collectionView.frame = [self filterBankFrameForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];

which uses the statusBarOrientation property to launch correctly in either landscape or portrait.

它使用statusBarOrientation属性在横向和纵向中正确地启动。

The willRotate / didRotate methods both give you a parameter you can pass to your frame generating method.

willRotate / didRotate方法都为您提供了可以传递给框架生成方法的参数。

Your method gives you the right frame size, then it's all up to you to pass down this info and manipulate your view hierarchy accordingly. It's easier than it sounds...

您的方法为您提供了正确的帧大小,然后由您来传递此信息并相应地操作您的视图层次结构。这比听起来容易……

(in your case, it looks like launcher would implement the methods, then coordinate the adjustments to launch1 and then down to search and finally to Search_custom_views)

(在您的示例中,好像launcher将实现这些方法,然后协调对launch1的调整,然后再到search,最后到Search_custom_views)

(**last side note, you'll make more friends here by choosing SearchCustomViews instead of Search_custom_views)

(**最后注意,您将通过选择searchcustomview而不是Search_custom_views来结交更多的朋友)