简体   繁体   中英

Different Nibs for different devices

So I'm writing an app, and I want it to be universal. When I created the project, I created a universal app. I have written all the iPhone code and have like 10 classes. Now I want to create the iPad version. Rather than have two sets of classes with basically the exact same code, I would like to load a different Nib based on the device type.

I tried using a BOOL in the app delegate and had trouble with that. I tried a device check in the mainViewController class (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil I returned a differnt nib based on the device type. But I could only get the iphone version or a blank nib. Thanks in advance for any help.

According to documentation (Resource programming guide) you can use name convention like: myNibName~ipad.xib and myNibName~iphone.xib so each file will be opened only on supported device. You don't even need to set different appDelegates :)

--- from doc --- In iOS 4.0 and later, it is possible to mark individual resource files as usable only on a specific type of device. This capability simplifies the code you have to write for Universal applications. Rather than creating separate code paths to load one version of a resource file for iPhone and a different version of the file for iPad, you can let the bundle-loading routines choose the correct file. All you have to do is name your resource files appropriately.

To associate a resource file with a particular device, you add a custom modifier string to its filename. The inclusion of this modifier string yields filenames with the following format:

.

The string represents the original name of the resource file. It also represents the name you use when accessing the file from your code. Similarly, the string is the standard filename extension used to identify the type of the file. The string is a case-sensitive string that can be one of the following values:

~ipad - The resource should be loaded on iPad devices only. ~iphone - The resource should be loaded on iPhone or iPod touch devices only.

Apple now provides you with a default mechanism to separate your code between iPhone and iPad while in the same project.

In Xcode 4, when you create a new "Window-based Application" or "View-based Application", you are given the option to select a "Device Family". If you select "Universal" for this option, Xcode will create 3 app delegates.

First, a main app delegate:

YourAppNameAppDelegate : NSObject <UIApplicationDelegate> 

and two other app delegates (placed in separate groups) that are subclasses of "YourAppNameAppDelegate":

YourAppNameAppDelegate_iPhone : YourAppNameAppDelegate
YourAppNameAppDelegate_iPad : YourAppNameAppDelegate

When you run your app with either the iPhone or iPad simulator (or device), the application will automatically use either the _iPhone or _iPad app delegate subclass based on the device chosen.

If you override application:didFinishLaunchingWithOptions: method in each subclass, you will see this working:

// In YourAppNameAppDelegate_iPhone.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"iPhone App Delegate");
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

// In YourAppNameAppDelegate_iPad.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"iPad App Delegate");
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

This gives you a starting point where you can alter program flow based on the device the user is on. For instance by instantiating one of the subclasses of your main view controller (as described below).

As you add new view controllers to your project, you should continue with this paradigm by creating one generic controller superclass, and an iPhone/iPad specific subclass. Note that the generic superclasses should not have nib files associated with them, while the subclasses should each have their own separate nib.

That way you can break your code between the three classes, keeping things that are platform independent in the superclass - for instance some properties, methods, IBOutlets, and IBActions - and place the platform specific implementations into either subclass.

I've had this problem, and I solved it by customizing the UIViewController's initWithNibName:bundle: method.

- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
  // See below for definition of "LWEUniversalAppHelpers fileNamed:"
  NSString *universalNibName = [LWEUniversalAppHelpers fileNamed:nibNameOrNil];
  if ((self = [super initWithNibName:universalNibName bundle:nibBundleOrNil]))
  {
    // Custom initialization
  }
  return self;
}

LWEUniversalAppHelpers is a helper class my company has written to determine if the device is an iPad or not. It's public on GitHub , but the basic concept is to use the "@2x" policy of Retina, but instead we use "@HD".

I figured out how:

in Interface Builder, use File->Create ipad version

then Save the file, and add it to the project. Then when alloc, init each viewController, check if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad , and else its an iPhone or iPod Touch. I've had trouble making edits to it after the initial save, but it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM