UIScrollView 在方向更改时没有获得新的大小

Posted

技术标签:

【中文标题】UIScrollView 在方向更改时没有获得新的大小【英文标题】:UIScrollView not getting new size on orientation change 【发布时间】:2010-07-11 01:05:24 【问题描述】:

我有一个非常简单的UIScrollView 示例,它根本没有做它应该做的事情。 不确定这是 API 的错误还是我的代码中的错误。

基本上,我有一个UIViewController 和一个UIScrollView 作为它的视图。 当我将它添加到 UIWindow 并更改 iPad 的方向时,我会注销 UIScrollViews 大小,这是错误的(?)报告。

这是我的UIViewController 实现:

@implementation CustomViewController
- (void)loadView 
  scrollView = [[[UIScrollView alloc] init] autorelease];
  scrollView.delegate = self;
  scrollView.backgroundColor = [UIColor redColor];
  self.view = scrollView;


- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
  CGSize rect = scrollView.frame.size;
  NSLog(@"will rotate w%f h%f", rect.width, rect.height);


- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
  CGSize rect = scrollView.frame.size;
  NSLog(@"will animate rotation w%f h%f", rect.width, rect.height);


- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
  CGSize rect = scrollView.frame.size;
  NSLog(@"did rotate w%f h%f", rect.width, rect.height);


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
  return YES;


@end

当我运行上述代码时,我在控制台中看到以下条目:

2010-07-11 11:03:05.214 Untitled2[6682:207] will rotate w768.000000 h1004.000000
2010-07-11 11:03:05.214 Untitled2[6682:207] will animate rotation w748.000000 h1024.000000
2010-07-11 11:03:05.619 Untitled2[6682:207] did rotate w748.000000 h1024.000000
2010-07-11 11:03:07.951 Untitled2[6682:207] will rotate w748.000000 h1024.000000
2010-07-11 11:03:07.958 Untitled2[6682:207] will animate rotation w768.000000 h1004.000000
2010-07-11 11:03:08.367 Untitled2[6682:207] did rotate w768.000000 h1004.000000

如您所见,方向更改确实调整了UIScrollView 的大小,但仅允许新的状态栏。 我预计宽度和高度会发生巨大变化,因为UIScrollView 的宽度大于高度,反之亦然。

有没有办法让UIScrollView 报告它的真实大小?

【问题讨论】:

【参考方案1】:

如果你还在寻找,我有答案。测试边界,而不是框架。

原因:frame 是边界的派生属性,并且应用于旋转的变换。

【讨论】:

这不起作用。我拦截了一个更改,然后我使用 NSStringFromRect(self.bounds) 并打印“就在更改之前”边界。但是 currentDevice 方向返回正确的值。至少那个人总是正确地返回同样的东西,但是伙计......这个问题不应该花这么长时间。从文档中,虽然 bounds 是非派生的,但它不总是 0,0,与框架宽度相同,与框架高度相同吗? 默认情况下边界原点始终为 0,0,除非您更改要显示的视图部分。这只是故事的一半,CGRect 也包含一个 size 成员,当您调整大小、重新定位视图时,这通常会发生变化。上面的“will”函数为您提供“之前的值”,“did”函数为您提供“之后的值”。【参考方案2】:

当它们的父视图调整大小时,视图不会自动调整大小,除非您特别设置它们。对于该滚动视图,您需要告诉它在其父视图执行时调整其宽度和高度。

scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

【讨论】:

不幸的是,在添加调整大小蒙版后,我仍然会返回无效尺寸。视觉上一切都很好,但我不能依赖框架尺寸。我通过检测设备方向并在横向时翻转宽度和高度来解决它 - 这并不理想,但它可以工作。 你需要测试 [[UIDevice currentDevice] 方向] 并看到这个: UIDeviceOrienationIsPortrait() 或类似的测试它。框架将是错误的,但它会报告正确的方向。这很烦人,我现在正在处理它,但很高兴有些东西是可靠的。也许边界答案会帮助我自动调整 UIScrollView 的大小,但即使在手动更改数学以匹配方向之后,我的也是不平衡的【参考方案3】:

我注意到,如果您从 iPhone NIB 文件而不是专用的 iPad NIB 文件开始,确定 didRotateFromInterfaceOrientation 中的新 contentSize 也是不可能的:iPhone NIB 文件中的帧要小得多,因此计算出来的内容高度比实际使用 iPad 时的高度要大得多。 Apple 确实说过我必须创建一个单独的 iPad NIB 文件...

所以,我也确实得到了 didRotateFromInterfaceOrientation 中的旧尺寸,但对我来说现在问题不大,因为一旦我开始使用正确的 NIB 文件,ios 确实可以处理所有事情。不过,在我看来,didRotateFromInterfaceOrientation 方法中的框架尺寸对于当前视图来说是不正确的。

附言。我最终确实找到了解决方案,只需使用通知而不是didRotateFromInterfaceOrientation

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(orientationChanged:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];

然后在orientationChanged 方法中,将视图调整为新帧。我遇到了最后一个问题:如果初始方向与笔尖中的方向不同,视图仍然是错误的,我通过创建一个新的 NIB 文件来解决这个问题,特别是针对横向视图。在 init 方法中,ViewController 根据当前方向选择它加载的 NIB。

【讨论】:

【参考方案4】:

我不知道它对你有帮助,因为我从未测试过,但我认为它可能对你有帮助

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
self.view = scrollView;
CGSize rect = scrollView.frame.size;
NSLog(@"will rotate w%f h%f", rect.width, rect.height);


- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
self.view = scrollView;    
CGSize rect = scrollView.frame.size;
NSLog(@"will animate rotation w%f h%f", rect.width, rect.height);


- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
 self.view = scrollView;
 CGSize rect = scrollView.frame.size;
 NSLog(@"did rotate w%f h%f", rect.width, rect.height);


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
return YES;
   

【讨论】:

【参考方案5】:

我通常通过将contentSize 的一个值设置为 0 来解决此问题,例如用于水平视图的CGSizeMake(contentSize.width, 0)

强制UIScrollView 仅滚动,例如水平将contentSize 的不可滚动值设置为 0 > CGSizeMake(contentSize.width, 0)

希望对你有帮助。

【讨论】:

以上是关于UIScrollView 在方向更改时没有获得新的大小的主要内容,如果未能解决你的问题,请参考以下文章

更改界面方向时UIScrollView上的奇怪跳转(ATPagingView)

IOS 中方向更改后包含 UIImageView 的 UIScrollView 的布局不正确

如何以编程方式自动旋转UIScrollView和UIImageView?

UIScrollView contentOffset 在方向更改后损坏

UIScrollViews 子视图没有在纵向到横向方向更改上调整自己的大小

如何更改 UIScrollView 中的滚动方向?