Tint a UIView with all its subviews

2019-02-05 04:32发布

问题:

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.

回答1:

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


回答2:

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.