navigationBar setBackgroundImage not working on iOS15

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.navigationController.navigationBar setBackgroundImage:[self imageWithColor:[UIColor redColor]] forBarMetrics:UIBarMetricsDefault];
}

- (UIImage *)imageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

it works on iOS14, but on iOS15. it doesn't work. the color of navigationBar does't change

Answered by Frameworks Engineer in 679484022

As of iOS 15, UINavigationBar, UIToolbar, and UITabBar will use their scrollEdgeAppearance when your view controller's associated scroll view is at the appropriate edge (or always if you don't have a UIScrollView in your hierarchy, more on that below).

You must adopt the UIBarAppearance APIs (available since iOS 13, specializations for each bar type) to customize this behavior. UIToolbar and UITabBar add scrollEdgeAppearance properties for this purpose in iOS 15.

For your specific case, the customization code looks something like this:

UINavigationBarAppearance *app = [UINavigationBarAppearance new];
[app configureWithOpaqueAppearance];
app.backgroundColor = UIColor.redColor;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance = app;

Keep in mind as well that you can also customize the standardAppearance and scrollEdgeAppearance of a specific UINavigationItem if your goal is only to change the appearance for a single view controller.

As for the UIScrollView comment above, if you do have a scroll view, but UIKit is not finding it (i.e. your bars are not responding to scroll it), we also added -[UIViewController setContentScrollView:forEdge:] to allow you to directly specify the scroll view to use.

Accepted Answer

As of iOS 15, UINavigationBar, UIToolbar, and UITabBar will use their scrollEdgeAppearance when your view controller's associated scroll view is at the appropriate edge (or always if you don't have a UIScrollView in your hierarchy, more on that below).

You must adopt the UIBarAppearance APIs (available since iOS 13, specializations for each bar type) to customize this behavior. UIToolbar and UITabBar add scrollEdgeAppearance properties for this purpose in iOS 15.

For your specific case, the customization code looks something like this:

UINavigationBarAppearance *app = [UINavigationBarAppearance new];
[app configureWithOpaqueAppearance];
app.backgroundColor = UIColor.redColor;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance = app;

Keep in mind as well that you can also customize the standardAppearance and scrollEdgeAppearance of a specific UINavigationItem if your goal is only to change the appearance for a single view controller.

As for the UIScrollView comment above, if you do have a scroll view, but UIKit is not finding it (i.e. your bars are not responding to scroll it), we also added -[UIViewController setContentScrollView:forEdge:] to allow you to directly specify the scroll view to use.

navigationBar setBackgroundImage not working on iOS15
 
 
Q