Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I animate tintColor to gray on a custom-drawn control when a sheet/alert is shown in iOS 7?

In iOS 7, when a UIActionSheet is presented, the system controls all animate their tintColor to gray. When the sheet is dismissed, they animate back.

I have some controls with custom background images or drawRect implementations that use the tint color, and I'd like them to animate that change just like the system controls.

Apple added - (void)tintColorDidChange to UIView, but redrawing with the new color in this method doesn't animate the change — it just switches from full color to full gray immediately, which looks bad when other system controls around it are animating.

How can I make my custom-drawn controls animate the tintColor transition like Apple's?

like image 277
Marco Avatar asked Nov 05 '13 20:11

Marco


3 Answers

You can do this with a Core Animation transition applied to the view layer:

//set up transition
CATransition *transition = [CATransition animation];
transition.type = kCATransitionFade;
transition.duration = 0.4;
[self.layer addAnimation:transition forKey:nil];

//now trigger a redraw of the background using the new colour
//and the transition will cover the redraw with a crossfade
self.flagToIndicateColorShouldChange = YES;
[self setNeedsDisplay];

EDIT: there may be a race condition between the animation and the redraw depending on exactly how you do the redraw. If you can post the original redraw code you tried that updated immediately (without animation) I can provide a more specific answer.

like image 71
Nick Lockwood Avatar answered Nov 02 '22 05:11

Nick Lockwood


Have you tried tintAdjustmentMode?

You should watch WWDC 2013 Session 214 Customizing Your App’s Appearance for iOS 7 and read the TicTacToe demo app

Something like this

- (void)onPopupOpened
{
    [UIView animateWithDuration:0.3 animations:^{
        window.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
    }];

    popupView.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
    popupView.tintColor = [UIColor redColor];
}

- (void)onPopupClosed
{
    [UIView animateWithDuration:0.3 animations:^{
        window.tintAdjustmentMode = UIViewTintAdjustmentModeAutomatic;
    }];
}
like image 43
onmyway133 Avatar answered Nov 02 '22 05:11

onmyway133


Shouldn't drawRect: be called automatically for the animation to update for the new tintColor?

I've made a demo application that has three controls in the main view controller. The first is a button that brings up a standard action sheet. The second is a button that's there for observation (the tapped button is hard to compare to during the animation). The third is a custom UIView subclass that simply draws a rectangle of the view's tintColor. When tintColorDidChange is called, I call setNeedsDisplay, which in turn will call drawRect:.

I created a new application with one view controller:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [[UIApplication sharedApplication] keyWindow].tintColor = [UIColor blueColor];

    // Button to bring up action sheet
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame = (CGRect){10,30,300,44};
    [button setTitle:@"Present Action Sheet" forState:UIControlStateNormal];
    [button addTarget:self
               action:@selector(didTapPresentActionSheetButton:)
     forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];

    // Another button for demonstration
    UIButton *anotherButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    anotherButton.frame = (CGRect){10,90,300,44};
    [anotherButton setTitle:@"Another Button" forState:UIControlStateNormal];
    [self.view addSubview:anotherButton];

    // Custom view with tintColor
    TESTCustomView *customView = [[TESTCustomView alloc] initWithFrame:(CGRect){10,150,300,44}];
    [self.view addSubview:customView];
}

- (void)didTapPresentActionSheetButton:(id)sender
{
    UIActionSheet *as = [[UIActionSheet alloc] initWithTitle:@"Action Sheet"
                                                    delegate:nil
                                           cancelButtonTitle:@"Cancel"
                                      destructiveButtonTitle:@"Delete"
                                           otherButtonTitles:@"Other", nil];
    [as showInView:self.view];
}

where TESTCustomView is a UIView subclass with implementation as follows:

- (void)drawRect:(CGRect)rect
{
    NSLog(@"Drawing with tintColor: %@", self.tintColor);

    // Drawing code
    [super drawRect:rect];

    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(c, self.tintColor.CGColor);
    CGContextFillRect(c, rect);
}

- (void)tintColorDidChange
{
    [self setNeedsDisplay];
}

Running this application in the simulator shows that the custom view's tintColor is automatically animated with the standard UIButton instances in the view controller.

like image 6
Matt Zanchelli Avatar answered Nov 02 '22 07:11

Matt Zanchelli