7

Any way you can tint a UIView? Not the background color, but the entire UIView with all its subviews.

e.g - A UIView with an animation of a star rotating , i.e The UIView shape is constantly changing.

Yogev Shelly
  • 1,373
  • 2
  • 13
  • 24
  • 2
    You could add a new subview to fill the entire view frame, set a bg color to that subview and make it slightly transparent.... though it won't be 'tinting' really. – Darek Rossman Dec 05 '11 at 17:55
  • the target UIView isn't a rectangle, it has a unique shape, e.g a star. – Yogev Shelly Dec 05 '11 at 18:13
  • You have a star-shaped UIView with subviews in it? – Darek Rossman Dec 05 '11 at 18:16
  • just an example... it can be any non rectangle shape. – Yogev Shelly Dec 05 '11 at 18:42
  • 1
    i guess i can create an image from the view, tint it fully, and blend it over the UIView, but it won't be really tinting the UIView, so if the view shape is changing - a star animating, it wouldn't work. (In ActionScript3 you can use ColorTransform to really tint a view, i was looking for something like that, oh well) – Yogev Shelly Dec 05 '11 at 18:45
  • This isn't really my area of expertise, but I know you can blend images using Quartz. Check out Quartz 2D Programming Guide http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html, specifically the section titled Using Blend Modes with Images. It doesn't seem like you can animate the blend after that, but this may help you get on the right track. – Jose Ibanez Dec 05 '11 at 19:23

2 Answers2

7

Eventually I created a UIView category that enables tinting of a UIView, without filling the UIView rectangle, here it is :

Takes an image representation of the UIView, then colors it in the given UIColor, this category was created to replicate a UIButton default highlight behavior, so it also comes with a method that can activate that behavior and let the category handle all touch methods.

//------------------ .h Interface file ------- //

//
//  UIView UIView_Tint.h
//  BabyQA
//
//  Created by yogev shelly on 8/10/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>

#define tintColorClassicUIButton [UIColor colorWithWhite:0.0 alpha:0.5]

@interface UIView(Tint)

//proprties should not be used, use the methods decalred bellow
@property (nonatomic,retain) UIColor* tintColor;
@property(nonatomic,retain) UIImageView* tintImageView;
@property(nonatomic,assign) BOOL tintOnTouchActive;

-(void)tintToColor:(UIColor*)color;
-(void)clearTint;
-(void)enableTintOnTouchWithColor:(UIColor*)color;
-(void)disableTintOnTouch;

-(UIImage *)imageRepresentation;
-(UIImage*)imageRepresentationWithTintColor:(UIColor*)color;

@end



//------------------ .m Implementation file ------- //


//  UIView UIView_Tint.m
//  BabyQA
//
//  Created by yogev shelly on 8/10/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights not reserved - go wild!
//

#import "UIView Tint.h"
#import <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>

static char const * const tintImageViewKey = "tintImageView";
static char const * const tintColorKey = "tintColorKey";
static char const * const tintOnTouchActiveKey = "tintOnTouchActive";



@implementation UIView (Tint)
@dynamic tintImageView;
@dynamic tintColor;
@dynamic tintOnTouchActive;

-(void)enableTintOnTouchWithColor:(UIColor*)color
{
    self.tintColor = color; 
    self.tintOnTouchActive = TRUE;
}

-(void)disableTintOnTouch
{
    self.tintOnTouchActive = FALSE;

}


-(void)tintToColor:(UIColor*)color
{

    if(![self.tintColor isEqual:color] || !self.tintImageView)
    {
        self.tintColor = color;
        UIImage* tintImage = [self imageRepresentationWithTintColor:self.tintColor];
        self.tintImageView =  [[[UIImageView alloc] initWithImage:tintImage] autorelease];
    }

    [self addSubview:self.tintImageView];
}

-(void)clearTint
{
    [self.tintImageView removeFromSuperview];
}

-(void)clearTintWithSecondsDelay:(float)delay
{
    [self performSelector:@selector(clearTint) withObject:self afterDelay:delay];
}


#pragma mark - TouchToggling

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    if(self.tintOnTouchActive)
        [self tintToColor:self.tintColor];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    if(self.tintOnTouchActive)
        [self clearTintWithSecondsDelay:0.05];
}

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    if(self.tintOnTouchActive)
        [self clearTintWithSecondsDelay:0.05];
}

#pragma mark - TintingPart

-(UIImage *)imageRepresentation
{

    UIGraphicsBeginImageContext(self.bounds.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return img;    
}

-(UIImage*)imageRepresentationWithTintColor:(UIColor*)color
{
    UIImage* viewImage = [self imageRepresentation];
    viewImage = [self tintedImage:viewImage UsingColor:color];
    return viewImage;
}

-(UIImage *)tintedImage:(UIImage*)image UsingColor:(UIColor *)tintColor {
    UIGraphicsBeginImageContextWithOptions(image.size, NO, [[UIScreen mainScreen] scale]);
    CGRect drawRect = CGRectMake(0, 0, image.size.width, image.size.height);
    [image drawInRect:drawRect];
    [tintColor set];
    UIRectFillUsingBlendMode(drawRect, kCGBlendModeSourceAtop);
    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return tintedImage;
}


#pragma mark - Dynamic setters/getters for Associative References

-(void)setTintImageView:(UIImageView *)tintImageView
{
    objc_setAssociatedObject(self, tintImageViewKey, tintImageView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

-(UIImageView*)tintImageView
{
    return objc_getAssociatedObject(self , tintImageViewKey);
}


-(UIColor*)tintColor
{
    return  objc_getAssociatedObject(self , tintColorKey);
}

-(void)setTintColor:(UIColor *)tintColor
{
    objc_setAssociatedObject(self, tintColorKey, tintColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(BOOL)tintOnTouchActive
{
    return [objc_getAssociatedObject(self, tintOnTouchActiveKey) boolValue];
}

-(void)setTintOnTouchActive:(BOOL)tintOnTouchActive
{
    objc_setAssociatedObject(self, tintOnTouchActiveKey, [NSNumber numberWithBool:tintOnTouchActive], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
jowie
  • 8,028
  • 8
  • 55
  • 94
Yogev Shelly
  • 1,373
  • 2
  • 13
  • 24
4

To tint a UIView, add another subview on top of it with the same frame and an alpha transparency set.

For example let's say your container type view is called containerView, you'd do as follows:

CGRect overlayFrame = containerView.frame;
UIView *overlayView = [UIView alloc] initWithFrame:overlayFrame];
overlayView.alpha = 0.5f;
overlayView.color = [UIColor blackColor];

[containerView addSubview:overlayView];

This gives you a semi transparent (0.5f) black tint that will give a tint like appearance to all the subviews underneath.

Max MacLeod
  • 26,115
  • 13
  • 104
  • 132
  • 1
    If the view for tinting has some transparency, this will tint through to the 'underneath' (i.e. a rectangular area is tinted). You could get around this by using a mask layer, I think. – occulus May 03 '12 at 13:30