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?
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.
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;
}];
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With