Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Button tint changes color when using popViewControllerAnimated

In View #1 I have two controls that are set in the storyboard; one is a UIBarButtonItem in the nav bar, the other is a UISegmentedController. The former is a custom-drawn image, and both items have their tint set to a purple color (tint set in the storyboard attributes inspector).

Through various actions, the user can get to View #2 via View #1. If a certain condition is not met when in View #2, the user is displayed an error message, and is redirected back to View #1 upon clicking "OK".

Pertinent Code:

if(i == [self.itemsAvailable count]){
    UIAlertView *alertView = [[UIAlertView alloc] 
                    initWithTitle:@"Oh no!" 
                    message:@"Warning message text!" 
                    delegate:self 
                    cancelButtonTitle:@"OK" 
                    otherButtonTitles:nil, nil];

    [alertView show];

    break;
}

Note that the alert is triggered within a while loop, hence the break;. The following function then returns to View #1

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == [alertView cancelButtonIndex]) {
        // Jump back one screen
        [self.navigationController popViewControllerAnimated:YES];
    }
}

The thing is, when I return to View #1 using the popViewControllerAnimated:YES function, the two controls mentioned previously (the UIBarButtonItem and the UISegmentedController) have their tints showing as grey instead of the desired purple.

Selecting a different UISegmentedController value brings back the appropriate tint color, but I need to leave View #1 for the UIBarButtonItem to return to the proper purple tint.

How come the tint colors are changing, and how can I remedy this issue so that they automatically have the appropriate tint colors upon popping back to View #1?

Note:

View #1 has the following viewWillAppear function

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];

    // Unhide the nav bar (hidden on home screen)
    [self.navigationController.navigationBar setHidden:NO];

    [self setUserDefaults]; // Load the appropriate values and set in UISegmentedController
}

where

- (void) setUserDefaults {

    // Set the defaults from the settings
    int selectedValue;

    selectedValue = (int)[self.userDefaults integerForKey:@"SomeValue"];        

    [self.defaultsSegment setSelectedSegmentIndex:selectedValue];
}

Some variable names have been modified and some code has been omitted, but this is the important parts. I do not believe that the function has anything to do with the incorrect tint color, because the UIBarButtonItem is never modified through code and is showing the same error as the UISegmentedController.

Edit #1:

Adding the line [self loadView]; to the viewWillAppear method fixes the UISegmentedController tint color, but I cannot yet figure out how to fix the UIBarButtonItem tint problem. Using the line [self.navigationController loadView]; causes a whole mess of issues.

Edit #2:

The UIAlertView is called within a method that itself is called from viewWillAppear. If I move the method call to viewDidAppear then the UIBarButtonItem retains its proper tint color. But then the graphics within the view suddenly appear AFTER the view has finished loading - which is unsightly.

like image 739
Birrel Avatar asked Oct 31 '22 21:10

Birrel


1 Answers

The reason for the issues is that the popViewControllerAnimated was called before the view had finished loading.

It went like this...

Within the viewWillAppear method was a call to another method that checked a condition and decided whether to pop up one view or not. The whole thing happened before the view had even finished loading, and that is where the problem came in.

Try putting this in View #2 and then navigating to it from View #1:

- (void)viewWillAppear:(BOOL)animated{
{
    [super viewWillAppear:animated];
    [self.navigationController popViewControllerAnimated:YES];
}

The code will compile just fine, but when you navigate to View #2 you will get the following log:

"nested pop animation can result in corrupted navigation bar"

And essentially that is the problem that I was experiencing with the tint colors changing after the pop. The method popViewControllerAnimated was deep enough in the code that it was not caught by Xcode, but not so far that it didn't create a bunch of problems.

The workaround that I did was the following:

  1. Create a BOOL variable @property (nonatomic) BOOL didFail;
  2. Set the BOOL variable to FALSE first thing in willViewAppear
  3. Call the method (within willViewAppear) that tests the condition
  4. If condition fails, set BOOL variable to TRUE
  5. Within viewDidAppear check to see if the BOOL variable is true or not. Pop up one view if condition is what you are looking for.

CODE:

.h file

@property (nonatomic) BOOL didFail;

.m file

- (void)viewWillAppear:(BOOL)animated{
{
    [super viewWillAppear:animated];
    self.didFail = FALSE;

    [self methodCall];
}

- (void) methodCall
{
    if(condition is met){
        self.didFail = TRUE;
    }
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    if(self.didFail == TRUE){
        //alert message
        [self.navigationController popViewControllerAnimated:YES];
    }
}

And that'll about do it. There is a slight pause before the alert shows up, but it is negligible. And now after the pop everything is exactly as it should be!

like image 61
Birrel Avatar answered Nov 12 '22 19:11

Birrel