基于 Xcode 页面的应用程序界面轮换问题
Posted
技术标签:
【中文标题】基于 Xcode 页面的应用程序界面轮换问题【英文标题】:Xcode Page Based Application Interface Rotation Issue 【发布时间】:2012-09-25 21:16:40 【问题描述】:-
在 Xcode 中启动一个新的基于页面的应用程序项目
运行项目,翻几页
旋转模拟器或设备
=> 页面视图控制器切换回第一页(1 月)
如何防止第 4 步?
编辑: 这仅在您在模拟器/设备中启动应用程序后第一次旋转时发生。 我在我的测试设备上使用带有 ios 6.0 模拟器和 iOS 6 的最新 Xcode 4.5。 当我从博客 / 等下载一些其他示例代码时,也会发生同样的事情。也许是 iOS 6 错误?
编辑2: 我发现传递给 UIPageViewController 的第一个页面视图在第一次旋转之前不会被释放。这对我来说真的像一个错误。
【问题讨论】:
【参考方案1】:(2014 年更新:如果您从新的 Page View 应用程序模板重新开始,这似乎已在 iOS7 中修复。)
我也遇到过这个错误。它似乎在主视图重新出现后随时启动。我的应用程序中有几个全屏模式,在这些模式消失后会发生相同的行为。
这发生在 XCode 4.5.1 和 iOS6 中 - 我通过重新下载 XCode 4.4 并将我的应用程序恢复到 iOS5.1 来“修复”了这个问题。显然不是一个很好的长期解决方案。我在 Radar 中提交了这个文件,并收到了一个通知,说它已经被记录了。
FWIW 我注意到 iBooks 在 iOS6 发布后就存在同样的错误,但他们似乎在最近的更新中修复了它。
【讨论】:
【参考方案2】:以下是我设法在我的应用中解决此问题的方法。恐怕这是一种 hacky 解决方案,但它是一个古怪的错误。
上下文:我的应用程序是一本日记本(称为 Remembary),每一页都是不同日期的日记条目。我有一个名为“AppContext”的单例类,它跟踪各种应用程序级别的值,例如当前显示的日记条目对象、当前日期等。每天的 dataViewController 也会跟踪自己的日记条目。
最棘手的部分是找到一个上下文,我可以在其中发现应用程序显示了错误的页面。原来这是在[RootViewController viewDidLayoutSubviews]中,所以我在那个方法中添加了以下内容:
// get the currently displaying page
DataViewController *currentPage = self.pageViewController.viewControllers[0];
// check if we're showing the wrong page
if ([currentPage myEntry] != [AppContext getCurrentEntry])
// jump to the proper page (the delay is needed to ensure that the rotation has fully completed)
[self performSelector:@selector(forceJumpToDate:)
withObject:[AppContext getCurrentEntryDate]
afterDelay:0.5];
这里是 forceJumpToDate 函数,它基本上是根据当前日期获取一个新页面,并告诉 pageViewController 在没有动画的情况下跳转到它:
- (void) forceJumpToDate:(NSDate *)targetDate
DataViewController *targetPage = [self.modelController viewControllerForDate:targetDate
storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:targetPage];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
当新页面被强制进入时,用户可能会注意到屏幕上出现了短暂的打嗝,但这只有在他们会得到错误页面的情况下才会发生,所以它仍然是一个改进。
这严重影响了我将应用升级到 iOS6 的能力,所以我很高兴我终于弄明白了。
【讨论】:
非常感谢您的回答!似乎延迟不仅需要等到轮换完成。事实上,延迟确实具有魔力。当旋转已经完成时,我在 didRotateFromInterfaceOrientation 中调用我的 forceJump 选择器,但它没有延迟工作。【参考方案3】:这是我的解决方案:
// RootViewController.m
#import "RootViewController.h"
#import "ModelController.h"
#import "DataViewController.h"
@interface RootViewController ()
@property (readonly, strong, nonatomic) ModelController *modelController;
//added
@property (strong, nonatomic) DataViewController *currentViewController;
@end
@implementation RootViewController
@synthesize modelController = _modelController;
//added
@synthesize currentViewController = _currentViewController;
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
//added
self.currentViewController = self.pageViewController.viewControllers[0];
- (void)didReceiveMemoryWarning
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
- (ModelController *)modelController
// Return the model controller object, creating it if necessary.
// In more complex implementations, the model controller may be passed to the view controller.
if (!_modelController)
_modelController = [[ModelController alloc] init];
return _modelController;
#pragma mark - UIPageViewController delegate methods
/*
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
*/
//added
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
self.currentViewController = self.pageViewController.viewControllers[0];
- (DataViewController *)currentViewController
if (!_currentViewController) _currentViewController = [[DataViewController alloc] init];
return _currentViewController;
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
if (UIInterfaceOrientationIsPortrait(orientation) || ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone))
// In portrait orientation or on iPhone: Set the spine position to "min" and the page view controller's view controllers array to contain just one view controller. Setting the spine position to 'UIPageViewControllerSpineLocationMid' in landscape orientation sets the doubleSided property to YES, so set it to NO here.
//deleted: UIViewController *currentViewController = self.pageViewController.viewControllers[0];
//changed to self.currentViewController
NSArray *viewControllers = @[self.currentViewController];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:NULL];
self.pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMin;
// In landscape orientation: Set set the spine location to "mid" and the page view controller's view controllers array to contain two view controllers. If the current page is even, set it to contain the current and next view controllers; if it is odd, set the array to contain the previous and current view controllers.
// deleted: DataViewController *currentViewController = self.pageViewController.viewControllers[0];
//deleted: NSArray *viewControllers = nil;
//added
NSArray *viewControllers = @[self.currentViewController];
//changed currentViewController to self.currentViewController
NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:self.currentViewController];
if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0)
UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:self.currentViewController];
viewControllers = @[self.currentViewController, nextViewController];
else
UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:self.currentViewController];
viewControllers = @[previousViewController, self.currentViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
return UIPageViewControllerSpineLocationMid;
@end
【讨论】:
谢谢!这对我有用。我已经看过有关此的帖子,但是这段代码清楚地表明了事情应该去的地方并且更加清晰。【参考方案4】:你想防止什么?你想防止旋转吗?如果这是您想要的,请修改 RootViewController.m 实现文件中的 shouldAutorotateToInterfaceOrientation 返回值。
当我这样做时,即使在旋转设备后,应用程序也能够保持相同的页面(月份)。我使用模拟器并在 iPhone 和 iPad 上进行了尝试。在 iPad 上,在横向模式下,它一次显示两个月,但当旋转回纵向时,仍然保留显示的两个月中的第一个。这是我增加到六月的时候。我使用了默认项目,没有更改任何代码。
【讨论】:
我无法复制返回首页的应用程序。 那是可悲的。但是,非常感谢您再次检查。您使用的是 Xcode 4.5 和 iOS 6.0 模拟器吗?【参考方案5】:今天我发现在我的应用程序中我可以使用以下内容来消除错误(但我不知道为什么)。
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
...
self.pageViewController.view.hidden = YES;
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
self.pageViewController.view.hidden = NO;
【讨论】:
以上是关于基于 Xcode 页面的应用程序界面轮换问题的主要内容,如果未能解决你的问题,请参考以下文章