【问题标题】:Can I use two xibs with one viewcontroller - re: porting to iPhone 5我可以在一个视图控制器上使用两个 xib - re: 移植到 iPhone 5
【发布时间】:2012-09-22 14:49:30
【问题描述】:

我刚刚将我的第一个应用提交到应用商店 (yay it was just approved!)。我现在想更新它以使用(看起来更好)更大的 iPhone 5 屏幕。除了为更大的屏幕稍微改变布局之外,我不打算改变任何东西。

注意:我不想拉伸当前的 xib。

是否可以创建两个 xib 文件(即:为主屏幕复制我当前的 xib 文件)并将它们都挂钩到视图控制器并拥有它,以便在应用启动时,应用检测是否有 iPhone 5 屏幕或更早的屏幕。然后,根据设备的不同,向用户显示不同的屏幕。

我打算让底层应用保持不变。我想要的只是为 iPhone 5 用户呈现一个稍微不同(更高)的屏幕,并为新布局移动一些按钮/项目。否则我不会在界面中添加或删除任何内容。

This SO question/answer 展示了如何在 iPhone 或 iPad 视图之间切换。 this one 也是如此。两者都有帮助,但我不知道如何针对用户使用更大屏幕的 iPhone 5 或 iPhone 4S 及以下的情况进行修改。此外,他们假设有两个视图控制器。我只想要一个视图控制器,因为视图控制器逻辑中绝对没有任何变化 - 只有屏幕上对象的位置发生变化,而这一切都在 XIB 中完成。

我应该认为答案应该是视图控制器iteslf评估它正在运行的设备然后呈现适当的xib?是的?没有?

如果是这样,我会怎么做?

【问题讨论】:

    标签: uiviewcontroller xib iphone-5


    【解决方案1】:

    [完整答案于 2012 年 10 月 7 日修订]

    经过大量研究,我找到了答案,部分在this SO page (which shows how to detect which iPhone version your app is running on),部分在this SO page (showing how to have two xib's share the same 'File's Owner'。我在The Big Nerd Ranch's excellent iOS Programming text 的第 10 章中找到了最后一块拼图(通过 loadNibNamed: 方法加载单独的 xib)。方法如下:

    1. 创建第二个 xib(文件,新建...,文件,选择“用户界面”,选择“空”并保存。这将创建新的 xib。在下面的示例中,我的经典 xib(对于3.5" iPhones) 被命名为 TipMainViewController.xib。我保存了新的 iPhone 5 xib,名称为 'TipMainViewController-5.xib'

    2. 使新 xib 的“文件所有者”与现有 xib 具有相同的 ViewController。为此,在新的 xib 文件中,选择“文件的所有者”。然后在“身份检查器”中选择现有的视图控制器作为自定义类。就我而言,我选择了“TipMainViewController”。

    3. 将新的 UIView 拖到新 xib 的空画布上。在新 UIView 的属性检查器中,将“Size”属性设置为“Retina 4 Full Screen”

    4. 选择现有 'Classic' 3.5" xib 中的所有内容 - 例如:所有控件、按钮、选择器、标签等。将它们复制并粘贴到新的 iPhone 5 xib 中。调整大小/移动等。以针对 iPhone 的 4 英寸显示屏进行优化。

    5. 像创建原始 xib 时那样建立与文件所有者的所有连接。

    6. 最后,在“单个”视图控制器的“viewDidLoad”方法中,插入以下逻辑(当然使用您的 nib/xib 名称):

      - (void)loadView
      {
          [super viewDidLoad];
          if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
          {
              CGSize result = [[UIScreen mainScreen] bounds].size;
              if(result.height == 480)
              {
                // iPhone Classic
                [[NSBundle mainBundle] loadNibNamed:@"TipMainViewController" owner:self options:nil];
              }
              if(result.height == 568)
              {
                // iPhone 5
                [[NSBundle mainBundle] loadNibNamed:@"TipMainViewController-5" owner:self options:nil];
              }
          }
      }
      

    【讨论】:

    • 这非常有用,对我帮助很大。
    • 我们应该检查自动布局选项吗?
    • 您的代码示例不起作用并且包含错​​字。不清楚您是指viewDidLoad 还是loadView
    • 您不应该在 initWithNibNameorNil: 方法中确定要加载哪个 nib 吗?当你点击 viewDidLoad 时,你已经加载了你的笔尖......
    • 我有一个名为 MasterScreen.xib 的文件,但源代码中没有任何loadNibNamed。我不知道该怎么办。我确实在源代码中看到了这样的东西:self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 我在我的任何项目文件中都没有看到MasterScreen.xib 引用(xcodeproj 文件除外)。创建新的 xib 文件后,我在哪里添加条件语句?我不知道,因为我什至不知道 MasterScreen.xib 是如何包含在应用程序中的。
    【解决方案2】:

    这是一个简单的工作代码示例,用于您的视图控制器,展示了如何在 iPhone 5 上加载 myXib-5.xib 和在 iPhone 5 之前的 iPhone/iPod 上加载 myXib.xib

    - (void)loadView
    {
        if([[UIScreen mainScreen] bounds].size.height == 568)
        {
            // iPhone 5
            self.view = [[NSBundle mainBundle] loadNibNamed:@"myXib-5" owner:self options:nil][0];
        }
        else
        {
            self.view = [[NSBundle mainBundle] loadNibNamed:@"myXib" owner:self options:nil][0];
        }
    }
    

    为了简单起见,它假设您只针对 iPhone 而不是 iPad。

    XIB 的文件所有者的类属性也应该设置为包含loadView 的视图控制器。

    【讨论】:

    • 复制xib,重命名副本(使用-5),放入您的代码。完毕。谢谢!
    【解决方案3】:

    答案中的代码很有帮助,但我需要一些更适合通用应用程序(iphone/ipad)的东西。

    如果其他人也需要同样的东西,这里有一些东西可以帮助您入门。

    假设您使用 ios 的 nib/xib 命名标准为具有相同名称的 xib 的视图控制器构建了一个通用应用程序:

    不提供名称时自动加载 xib 的两个内置默认值被传递给 initWithNibName:

    • ExampleViewController.xib [当 nib 为 Retina 3.5 全屏为经典布局 iphone 4/4s 等时,iphone 默认为空...]
    • ExampleViewController~ipad.xib [ipad/ipad mini 默认当 nib 命名为空时]

    现在说您需要使用 Retina 4 全屏选项在 IB 中为 iphone 5/5s 自定义 xib,即您不希望为任何 568h 设备显示 3.5 xib。

    这是使用类别方法的自定义命名约定:

    • ExampleViewController-568h.xib [当 Retina 4 全屏 (568h) 的 nib 名称为空时,iphone 非默认/自定义命名约定]

    不要覆盖内置命名默认值,而是使用类别来帮助为控制器设置正确的 xib。

    https://gist.github.com/scottvrosenthal/4945884

    ExampleViewController.m

    #import "UIViewController+AppCategories.h"
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        nibNameOrNil = [UIViewController nibNamedForDevice:@"ExampleViewController"];
    
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
    
           // Do any additional customization 
    
        }
    
        return self;
    }
    

    UIViewController+AppCategories.h

    #import <UIKit/UIKit.h>
    
    @interface UIViewController (AppCategories)
    
       + (NSString*)nibNamedForDevice:(NSString*)name;
    
    @end
    

    UIViewController+AppCategories.m

    // ExampleViewController.xib [iphone default when nib named empty for Retina 3.5 Full Screen]
    // ExampleViewController-568h.xib [iphone custom naming convention when nib named empty for Retina 4 Full Screen (568h)]
    // ExampleViewController~ipad.xib [ipad/ipad mini default when nib named empty]
    
    #import "UIViewController+AppCategories.h"
    
    @implementation UIViewController (AppCategories)
    
    + (NSString*)nibNamedForDevice:(NSString*)name
    {
    
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
        {
            if ([UIScreen mainScreen].bounds.size.height == 568)
            {
                //Check if there's a path extension or not
                if (name.pathExtension.length) {
                    name = [name stringByReplacingOccurrencesOfString: [NSString stringWithFormat:@".%@", name.pathExtension] withString: [NSString stringWithFormat:@"-568h.%@", name.pathExtension ]
                    ];
    
                } else {
                    name = [name stringByAppendingString:@"-568h"];
                }
    
                // if 568h nib is found
                NSString *nibExists = [[NSBundle mainBundle] pathForResource:name ofType:@"nib"];
                if (nibExists) {
                    return name;
               }
    
            }
        }
    
        // just default to ios universal app naming convention for xibs
        return Nil;
    }
    
    @end
    

    【讨论】:

    • 这离为我工作太近了。我正在使用情节提要,但从情节提要中的 VC 中删除视图并让每个 VC 从笔尖加载。在这样做时,我的 VC 正在使用 initWithCoder 进行初始化。我的理解是 initWithNibName 调用 initWithCoder 所以如果我尝试这个会有一些不愉快的循环。有什么想法可以为此调整您的方法吗?
    猜你喜欢
    • 2016-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多