基于Xcode页面的应用程序接口轮换问题

时间:2012-09-25 21:16:41

标签: objective-c ios xcode uipageviewcontroller

  1. 在Xcode中启动基于新页面的应用程序项目
  2. 运行项目并翻开一些页面
  3. 旋转模拟器或设备
  4. =>页面视图控制器切换回第一页(1月)
  5. 如何阻止第4步?

    编辑: 只有在应用程序在模拟器/设备中启动后第一次旋转时才会发生这种情况。 我在我的测试设备上使用最新的Xcode 4.5和iOS 6.0模拟器以及iOS 6。 当我从博客/等等下载一些其他示例代码时,会发生同样的事情。也许是iOS 6的错误?

    EDIT2: 我发现传递给UIPageViewController的第一个页面视图在第一次旋转之前不会被释放。这对我来说真的像个错误。

5 个答案:

答案 0 :(得分:4)

(2014年更新:如果您从新的“网页浏览”应用程序模板重新开始,这似乎已在iOS7中修复。)

我也经历过这个错误。在主视图重新出现后,它似乎随时可以启动。我的应用程序中有几个全屏模式,在这些模型消失之后会出现相同的行为。

这在XCode 4.5.1和iOS6中发生 - 我通过重新下载XCode 4.4并将我的应用程序恢复为iOS5.1来“修复”此问题。显然不是一个很好的长期解决方案。我在Radar中提交了这个,然后收到一条记录,说它已经被记录了。

FWIW我注意到iBooks在iOS6问世之后就出现了同样的错误,但他们似乎已经在最近的更新中解决了这个问题。

答案 1 :(得分:1)

以下是我在应用中设法解决此问题的方法。我担心这是一种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的能力,所以我很高兴我终于明白了。

答案 2 :(得分:1)

这是我的解决方案:


//  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

答案 3 :(得分:0)

你想要阻止什么?你想防止轮换吗?如果这是你想要的,修改RootViewController.m实现文件中的shouldAutorotateToInterfaceOrientation返回值。

当我这样做时,即使在旋转设备之后,应用程序也可以保持相同的页面(月份)。我使用了模拟器并试用了iPhone和iPad。在iPad上,在横向模式下,它一次显示两个月,但是当旋转回到肖像时,仍然保持显示的两个月中的第一个。这是我增加到六月的时候。我使用了默认项目而没有更改代码行。

答案 4 :(得分:0)

今天我发现在我的应用程序中我可以使用以下内容来删除错误(但我不知道为什么)。

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
        ...
         self.pageViewController.view.hidden = YES;
    }

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
        self.pageViewController.view.hidden = NO;
    }