UINavigationBar and new iOS 5+ appearance API - ho

2020-03-01 20:18发布

问题:

I want to exploit the new iOS 5 appearance API to supply custom background images to all UINavigationBar instances in my app. To do this, it's as simple as this:

[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"whatever.png"] forBarMetrics:UIBarMetricsDefault];

However, for each instance, I want to provide a different image depending on the value of the translucent property, e.g.

// For UINavigationBar instances where translucent returns YES:
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"whatever-translucent.png"] forBarMetrics:UIBarMetricsDefault];

// Otherwise:

[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"whatever.png"] forBarMetrics:UIBarMetricsDefault];

Given that the appearance APIs seem to be configured using class methods, is something like this possible?

回答1:

At the moment, there's no way to do what you're describing - the appearance proxy doesn't know anything about any particular instance at the time you're calling for it.

In practical terms, what you'll probably need to do is figure out how many translucent bars you'd have v. how many non-translucent ones you had. Choose whichever you have more of and use the appearance proxy for that one - for the others, when you go to make it translucent (or ask for full-screen layout), you'll have to set the background image then.

In the meantime, could you file an enhancement request at http://bugreport.apple.com/ for what you're asking? It's not an unreasonable request. Thanks!



回答2:

You can either set it globally with the class appearance proxy or set it on an instance of a navBar.

I'm currently setting background on an instance of the nav bar and it seems to be working. I have two different navBars with different backgrounds. If you set it on an instance, you should be able to condition the code.

UINavigationController *myNavController = [[UINavigationController alloc] initWithRootViewController:myView];
[viewControllers addObject:myNavController];

// not supported on iOS4
UINavigationBar *navBar = [myNavController navigationBar];
if ([navBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)])
{
    // right here, you could condition bg image based on properties of this instance
    // of the navBar or any other condition.

    [navBar setBackgroundImage:[UIImage imageNamed:@"bg.jpg"] forBarMetrics:UIBarMetricsDefault];
}

If you want to set using the class method, you can set for all:

[[UINavigationBar appearance] setBackground ...

I will admit though that it's pretty new and I'm just figuring it out like most folks.



回答3:

This answer probably won't be of much help to you, but it may be to others. IF you make a subclass, you can specify the appearance for each subclass separately. For instance, I have UITableviewCells and a custom class that is derived from UITableViewCells. I actually do this for a reason, but I discovered that i need to call [[UITableViewCells appearance] setFont:[...]] for both classes specifically.

Since you seem to want to do so based upon a variable that you will not know until runtime, you are probably out of luck!



回答4:

You can do it like this if you know which classes contain the translucent bars:

[[UIBarButtonItem appearanceWhenContainedIn:[MyClassWithTranslucentBar class], [MyOtherClassWithTranslucentBar class], nil]
    setTintColor:desiredColor];


回答5:

I cant leave a comment so will have to be an answer. Rob Whitlow wrote a great article on this. Check it out: http://ios-blog.co.uk/tutorials/ios-custom-ui-series-tabbar-navbar/



回答6:

Try this:

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {


        // Load resources for iOS 6.1 or earlier

         navigationController1 = [self customizedNavigationController];
         [navigationController1 setViewControllers:[NSArray arrayWithObject: self.homeViewController]];

         [self setNavigationController:navigationController1];
         [self.window setRootViewController:navigationController];


    } else {
        // Load resources for iOS 7 or later
         navigationController1 = [[UINavigationController alloc] initWithRootViewController:self.homeViewController];
          [self.window setRootViewController:navigationController1];
    }


  - (UINavigationController *)customizedNavigationController {

     UINavigationController *navController = [[UINavigationController alloc]   initWithNibName:nil bundle:nil];

    // Ensure the UINavigationBar is created so that it can be archived. If we do not access the
    // navigation bar then it will not be allocated, and thus, it will not be archived by the
    // NSKeyedArchvier.
    [navController navigationBar];

    // Archive the navigation controller.
    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [archiver encodeObject:navController forKey:@"root"];
    [archiver finishEncoding];

    // Unarchive the navigation controller and ensure that our UINavigationBar subclass is used.
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    [unarchiver setClass:[LNTNavigationBar class] forClassName:@"UINavigationBar"];
    UINavigationController *customizedNavController = [unarchiver decodeObjectForKey:@"root"];
    [unarchiver finishDecoding];

    // Modify the navigation bar to have a background image.
    LNTNavigationBar *navBar = (LNTNavigationBar *)[customizedNavController navigationBar];
    [navBar setTintColor:[UIColor colorWithRed:0.39 green:0.72 blue:0.62 alpha:1.0]];
    [navBar setBackgroundImage:[UIImage imageNamed:@"nav_bar_1024_46.png"] forBarMetrics:UIBarMetricsDefault];
    [navBar setBackgroundImage:[UIImage imageNamed:@"nav_bar_1024_46.png"] forBarMetrics:UIBarMetricsLandscapePhone];

    return customizedNavController;
}