开发者

Can I fade / animate the tintColor of a UIToolbar?

开发者 https://www.devze.com 2023-01-31 07:45 出处:网络
I am trying to animate a UIToolbar\'s tintColor property, to change it from one tintColor to another.

I am trying to animate a UIToolbar's tintColor property, to change it from one tintColor to another.

Here is the code I am trying. Unfortunately, the change occurs immediately and does not fade from green to blue. This is strange because I know Apple fades and "pulses" toolbar tint colors when tethering or on a phone call. So why doesn't this work?

// set initial tint color  
myBottomToolBar.tintColor = [UIColor colorWithRed:0.15 green:0.95 blue:0.15 alpha:0.6];
开发者_Go百科
//animation stuff  
[UIView beginAnimations:nil context:nil];  
[UIView setAnimationDuration:1.95];  
[UIView setAnimationDelegate:self];        

//thing to animate  
myBottomToolBar.tintColor = [UIColor colorWithRed:0.15 green:0.35 blue:0.45 alpha:0.6];

//animation stuff  
[UIView commitAnimations]; 


The tint color in not animatable through public APIs. You can work around this by manually changing the tint color on a timer. You would have to interpolate the intermediate color levels.


Each UIView has a tintAdjustmentMode:

The first non-default tint adjustment mode value in the view’s hierarchy, ascending from and starting with the view itself.

When this property’s value is dimmed, the value of the tintColor property is modified to provide a dimmed appearance.

For example, if you need to dim the current tintColor (dim = grey color) just use the code below:

// Assuming tintAdjustmentMode is set to .automatic
UIView.animate(withDuration: 0.5) {
   yourView.tintAdjustmentMode = .dimmed
}

This will animate the tintColor to grey and will dim it.

If you want to animate the tintColor to your own custom color:

// Make sure it is set to normal and not automatic
yourView.tintAdjustmentMode = .normal

UIView.animate(withDuration: 0.5) {
   yourView.tintColor = .black
}


For future reference, here's my somewhat hasty solution for animating tint. I'm sure there are more clever ways of doing this with categories and a struct for the rgb values yadda yadda. I was in a hurry, OK?!

UITabBarController subclass:

@interface BaseNavigationController : UINavigationController
{
    NSTimer *           tintTimer;
    UIColor *           targetColor;
}

-(void)changeTintTo:(UIColor*)color;
-(void)animateTint;

.

-(void)changeTintTo:(UIColor*)color;
{
    targetColor = [color retain];

    [tintTimer invalidate];
    tintTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(animateTint) userInfo:nil repeats:YES];

}

-(void)animateTint;
{
    UIColor * currentColor = self.navigationBar.tintColor;

    CGFloat red, green, blue, alpha;
    [currentColor getRed:&red green:&green blue:&blue alpha:&alpha];

    CGFloat targetRed, targetGreen, targetBlue, targetAlpha;
    [targetColor getRed:&targetRed green:&targetGreen blue:&targetBlue alpha:&targetAlpha];

    CGFloat newRed = red + ((targetRed - red)*.2);

    UIColor * newColor = [UIColor colorWithRed:newRed
                                         green:green + ((targetGreen - green)*.2)
                                          blue:blue + ((targetBlue - blue)*.2) // the .2 adjusts the fade speed
                                         alpha:1.0];

    if(
       (newRed < targetRed && newRed >= targetRed-0.01) || 
       (newRed > targetRed && newRed <= targetRed+0.01)
    )
    {
        newColor = targetColor;
        [targetColor autorelease];
        [tintTimer invalidate];
        tintTimer = nil;
        targetColor = nil;
    }

    self.navigationBar.tintColor = newColor;

}


NSTimer and it's setup is a lot of work for a simple animation. Here's my solution using dispatch, I'm just fading a UIBarButtonItem in and out by changing the alpha value of the tint color:

-(void)animateItemToTargetAlpha:(CGFloat)targetAlpha
{
    static dispatch_source_t timer = nil;
    static CGFloat DURATION = 0.25f;
    static CGFloat FPS = 30.f;
dispatch_source_cancel(timer);
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1/FPS * NSEC_PER_SEC,(1ull * NSEC_PER_SEC) / 10);

    CGFloat red, green, blue, __block alpha;
    [self.navigationItem.rightBarButtonItem.tintColor getRed:&red green:&green blue:&blue alpha:&alpha];

    dispatch_source_set_event_handler(timer, ^{
        alpha = targetAlpha == 1.0f ? alpha + (1/(FPS * DURATION)) : alpha - (1/(FPS * DURATION));
        self.navigationItem.rightBarButtonItem.tintColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
        if(alpha >= 1 || alpha  <= 0)
        {
            dispatch_source_cancel(timer);
        }
    });

    dispatch_resume(timer);
}

The linear curve can be a little noticeable but I'm interested in trying CADisplayLink first before making any changes.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号