【问题标题】:Problems with multiple xibs for rotation under iOS6iOS6下多个xib旋转的问题
【发布时间】:2013-06-30 09:35:33
【问题描述】:

我需要为纵向和横向使用不同的 xib 文件。我没有使用自动布局,但我使用的是 iOS6。 (如果您关心原因,请参阅 my previous question。)

我正在关注 Adam 对 this question 的回答,使用 amergin 的 initWithNib 名称技巧进行了修改,并根据我自己的 iPhone/iPad 需求进行了修改。这是我的代码:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{    
    [[NSBundle mainBundle] loadNibNamed:[self xibNameForDeviceAndRotation:toInterfaceOrientation]
                                  owner: self
                                options: nil];
    [self viewDidLoad];
}

- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation
{
    NSString *xibName ;
    NSString *deviceName ;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        deviceName = @"iPad";
    } else {
        deviceName = @"iPhone";
    }

    if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )
    {
        xibName = [NSString stringWithFormat:@"%@-Landscape", NSStringFromClass([self class])];
        if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
            return xibName;
        } else {
            xibName = [NSString stringWithFormat:@"%@_%@-Landscape", NSStringFromClass([self class]), deviceName];
            if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
                return xibName;
            } else {
                NSAssert(FALSE, @"Missing xib");
                return nil;
            }
        }

    } else {
        xibName = [NSString stringWithFormat:@"%@", NSStringFromClass([self class])];
        if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
            return xibName;
        } else {
            xibName = [NSString stringWithFormat:@"%@_%@", NSStringFromClass([self class]), deviceName];
            if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
                return xibName;
            } else {
                NSAssert(FALSE, @"Missing xib");
                return nil;
            }
        }
    }
}

当然我在做:

- (BOOL) shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

在我的视图控制器中:

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown);
}

在我的委托中。

我有两个可能相关的问题。第一,简单的。我不倒转。我在 iPad 和 iPhone 的 xcode 中打开了所有正确的位。这可能是一个单独的问题,也可能是我的问题的核心。

真正的问题是,当我旋转到横向模式时,我的 xib 被替换,但视图偏离了 90 度。

这是我的 2 xib 的样子。 (我给它们涂上了花哨的颜色,所以你可以看到它们是不同的。)

当我运行它(最初在横向模式下)时,您可以看到横向 xib 是正确的。

当我旋转到纵向时它也是正确的

但是当我旋转回横向时,xib 被替换,但视图偏离了 90 度。

这里有什么问题?

【问题讨论】:

  • 我认为您将 xib 加载到早期,您是否尝试将代码从 willRotatetToInterface.. 移动到 didRotateFrom...
  • hmmmm,这给了我从方向。由于我的应用程序基本上只有 2 个可能的应用程序,我想这没问题,但它似乎不干净......
  • 它也不起作用。洋红色现在是全宽的,但 UI 小部件仍然偏离 90 度。
  • 嗨,你找到解决问题的方法了吗,我目前也面临同样的问题,我发现的唯一方法是删除第二个 xib,并在代码中进行所有框架更改.. . :*(
  • 我遇到了同样的问题,但很难相信有这么多人说这对他们来说是正确的。是什么赋予了?在视图切换设计方面,我真的不想走得那么远。

标签: ios ios6 autorotate


【解决方案1】:

我可能一直在走与保罗·塞尚去年相同的道路。不确定他是否尝试过这个,但我解决了最初的问题(在这个问题中说明),只是让我的根控制器成为导航控制器而不是我的视图控制器类。由于我使用的是“空项目”模板和 XIB 文件,这意味着更改正常:

self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;

在 AppDelegate.m 中,改为:

self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
navigationController.navigationBar.hidden = YES;
self.window.rootViewController = navigationController;

也就是说,我刚刚创建了一个通用 UINavigationController 并将其设置为根视图控制器。

我不确定这是否会导致其他问题,并且可能有一种方法可以弄清楚(也许您需要源代码)UINavigationController 做了哪些 UIViewController 没有。可以像在正确的地方调用一个额外的 setNeedsLayout 类型一样简单。如果我弄明白了,我会为未来的读者编辑这个答案。

感谢Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape? 上的 Sakti 的 cmets,我第一次阅读时不应该忽略它们:

我将视图控制器添加到导航控制器并呈现它 这使它按预期工作

编辑:在示例代码中添加了额外的行以隐藏导航栏,因为大多数关注此问题的人都不希望这样做。

【讨论】:

  • 有趣的方法。如果它对我有用,它会简单得多。当然,那个特定的项目已经发货很久了,但我可能会再次打开它来尝试。我会投票只是因为它很聪明,不知道它是否会起作用。谢谢!
【解决方案2】:

这就是我的做法,它适用于 iOS 5+:

   - (void)viewDidLoad {
   [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(checkBagRotation)
                                             name:UIApplicationDidChangeStatusBarOrientationNotification
                                           object:nil];
  [self checkBagRotation];
 }

- (void)checkBagRotation {
    orientation = [UIApplication sharedApplication].statusBarOrientation;
    if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        [[NSBundle mainBundle] loadNibNamed:@"Controller-landscape"
                                      owner:self
                                    options:nil];
   } else {
        [[NSBundle mainBundle] loadNibNamed:@"Controller-portrait"
                                      owner:self
                                    options:nil];

}

【讨论】:

  • 我会试一试。我原以为委托方法会起作用,我很确定我上面的代码在 iOS5 下工作......
【解决方案3】:

我在这里回答我自己的问题,粘贴在我的 iOS 博客 http://www.notthepainter.com/topologically-challenged-ui/ 上的完整文章

我有一个朋友帮助我,他在一个带有 IBOutlets 的 xib 文件中使用了 2 个视图,用于纵向和横向视图,并且他在设备旋转时在它们之间切换。完美,对吧?好吧,不,当您在 XIB 中有 2 个视图时,您无法将 IBOutlets 连接到这两个位置。我让它在视觉上工作,但我的控件只在一个方向上工作。

我最终想出了使用方向主视图控制器的想法,该控制器在设备旋转时加载容器视图控制器。那工作得很好。让我们看一下代码:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
    if (_timerViewController) {
        [_timerViewController.view removeFromSuperview];
        [_timerViewController willMoveToParentViewController:nil];
        [_timerViewController removeFromParentViewController];
        self.timerViewController = nil;
    }

    self.timerViewController = [[XTMViewController alloc] initWithNibName:
          [self xibNameForDeviceAndRotation:interfaceOrientation withClass:[XTMViewController class]]
                                             bundle:nil];

    // use bounds not frame since frame doesn't take the status bar into account
    _timerViewController.view.frame = _timerViewController.view.bounds = self.view.bounds;

    [self addChildViewController:_timerViewController];
    [_timerViewController didMoveToParentViewController:self];
    [self.view addSubview: _timerViewController.view];
}

如果您阅读了我之前关于容器视图控制器的博客文章,那么 addChildViewController 和 didMoveToParentViewController 应该很熟悉。不过,在这些调用之上有两件事需要注意。我将首先处理第二个,我从父边界设置子视图控制器的框架和边界,而不是框架。这是为了考虑状态栏。

并注意调用 xibNameForDeviceAndRotation 以从其 xib 文件加载视图控制器。让我们看看这段代码:

- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation withClass:(Class) class;
{
    NSString *xibName ;
    NSString *deviceName ;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        deviceName = @"iPad";
    } else {
        deviceName = @"iPhone";
    }

    if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )  {
        xibName = [NSString stringWithFormat:@"%@-Landscape", NSStringFromClass(class)];
        if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
            return xibName;
        } else {
            xibName = [NSString stringWithFormat:@"%@_%@-Landscape", NSStringFromClass(class), deviceName];
            if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
                return xibName;
            } else {
                NSAssert(FALSE, @"Missing xib");
                return nil;
            }
        }
    } else {
        xibName = [NSString stringWithFormat:@"%@", NSStringFromClass(class)];
        if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
            return xibName;
        } else {
            xibName = [NSString stringWithFormat:@"%@_%@", NSStringFromClass(class), deviceName];
            if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) {
                return xibName;
            } else {
                NSAssert(FALSE, @"Missing xib");
                return nil;
            }
        }
    }
    return nil;
}

这里发生了很多事情。让我们回顾一下。我首先确定您使用的是 iPhone 还是 iPad。 xib 文件的名称中将包含 iPhone 或 iPad。接下来我们检查我们是否处于横向模式。如果是,我们从类名构建一个测试字符串,通过 NSStringFromClass 使用类反射。接下来,我们使用 pathForResource 检查 xib 是否存在于我们的包中。如果是,我们返回 xib 名称。如果没有,我们再次尝试将设备名称放入 xib 名称中。如果存在则返回它,如果不存在则断言失败。 Portrait 类似,但按照惯例,我们不会将“-Portrait”放入 xib 名称中。

这段代码足够有用和通用,我会把它放在我的 EnkiUtils 开源项目中。

由于这是 iOS6,我们需要放入 iOS6 轮换样板代码:

- (BOOL) shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAll;
}

奇怪的是,我们还需要在 iPad 上手动调用 willAnimateRotationToInterfaceOrientation。 iPhone 会自动获得 willAnimateRotationToInterfaceOrientation,但 iPad 不会。

- (void) viewDidAppear:(BOOL)animated
{
    // iPad's don't send a willAnimate on launch...
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        [self willAnimateRotationToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation] duration:0];
    }
}

那么,我们完成了吗?尴尬的是没有。你看,当我编写 XTMViewController 类时,我打破了模型-视图-控制器设计模式!这很容易做到,Apple 已经通过将 View 和 Controller 放在同一个类中来帮助我们。而且很容易在 VC 的 .h 文件中不小心混入模型数据。而我正是这样做的。当我运行上面的代码时,它运行良好,我可以整天旋转它,并且 UI 在两个方向上都是正确的。但是,当我在锻炼计时器运行时旋转设备时,您认为会发生什么?是的,它们都被删除了,UI 重置为初始状态。这根本不是我想要的!

我创建了一个 XTMUser 类来保存所有计时数据,我将所有 NSTimers 放入 XTMOrientationMasterViewController 类,然后我创建了一个协议,以便 XTMOrientationMasterViewController 可以响应 XTMViewController 类中的 UI 点击。

然后我就完成了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多