Search code examples
iosuicollectionviewuicollectionviewcellcalayercagradientlayer

Create gradient-based UICollectionViewCell background colour


I want to create custom bar for displaying some progress, that must look something like this:

enter image description here

So, as you can see each bar has it's own gradient background. I want to use UICollectionView for this. But problem is to create gradient background for each individual cell. So is it possible somehow create ONE basic gradient for whole UICollectionView, and then mask it, to be visible inside UICollectionViewCell?


Solution

  • Okay, here is the example, background is the gradient layer with different colours are spread and above you can create a mask layer to appear only on the rectangular shapes, which gives the illusion of the different rectangular layers having different gradient, you can play with gradient to get your desired effect,

    First you subclass the UIView or you can create directly, better you can create a subclass as I am doing in the example

    obj-c

    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if(self)
        {
            [self createGreadient];
        }
        return self;
    }
    
    //this create a grenadine with the rectangular mask layer
    - (void)createGreadient
    {
        UIColor *theColor = [UIColor redColor];//[[UIColor alloc] initWithRed:146.0/255.0 green:146.0/255.0 blue:146.0/255.0 alpha:1];
        CAGradientLayer *gradientLayer = [[CAGradientLayer alloc] init];
        gradientLayer.frame = self.bounds;
    
        //u can add your own colours to get your requirement
        gradientLayer.colors = [NSArray arrayWithObjects:
                                (id)[theColor CGColor],
                                (id)[[theColor colorWithAlphaComponent:0.7f] CGColor],
                                (id)[[theColor colorWithAlphaComponent:0.4f] CGColor],
                                (id)[[theColor colorWithAlphaComponent:0.3f] CGColor],
                                (id)[[theColor colorWithAlphaComponent:0.2f] CGColor],
                                (id)[[theColor colorWithAlphaComponent:0.1f] CGColor],
                                (id)[[UIColor clearColor] CGColor],nil];
        [self.layer addSublayer:gradientLayer];
    
        CAShapeLayer *layerMask = [[CAShapeLayer alloc] init];
        layerMask.frame = self.bounds;
        UIBezierPath *rectangularMaskPath = [self getRectangularMaskPathForCount:5];
        layerMask.path = rectangularMaskPath.CGPath;
    
        gradientLayer.mask = layerMask;
    
    }
    
     //this creates rectangular path, u can adjust the rectangular and u can 
    //pass different number of count as the progress proceeds 
    - (UIBezierPath *)getRectangularMaskPathForCount:(NSInteger)rectCount
    {
        UIBezierPath *path = [[UIBezierPath alloc] init];
        int i = 0;
        for(;i <= rectCount; i++)
        {
            UIBezierPath *aPath;
            CGRect aRect = CGRectMake(20+ (i * 20), 20, 10, 100); //set the rectangular position to your requirement
            aPath = [UIBezierPath bezierPathWithRect:aRect]; 
            [path appendPath:aPath];
        }
        return path;
    }
    

    swift version subclass the UIView and past the below code,

     override init (frame : CGRect) {
        super.init(frame : frame)
        createGreadient()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    
    func createGreadient()
    {
        let  color:UIColor = UIColor.red
        let greadetLayer = CAGradientLayer.init()
    
        greadetLayer.frame = self.bounds
        greadetLayer.colors = [color.withAlphaComponent(0.8).cgColor,color.withAlphaComponent(0.7),color.withAlphaComponent(0.4).cgColor,color.withAlphaComponent(0.3).cgColor,color.withAlphaComponent(0.2),color.withAlphaComponent(0.1).cgColor]
    
        self.layer .addSublayer(greadetLayer)
        let rectangularMaskPath  = self.creatrRectangularPathWithCount(countRect: 5)
        let maskLayer:CAShapeLayer = CAShapeLayer()
        maskLayer.frame = self.bounds
        maskLayer.path = rectangularMaskPath.cgPath
        greadetLayer.mask = maskLayer
    
    }
    
    
    func creatrRectangularPathWithCount(countRect:NSInteger) -> UIBezierPath {
        let path : UIBezierPath = UIBezierPath()
        for i in 0..<countRect {
           let aPath = UIBezierPath.init(rect: CGRect(x: 20 + (i * 20), y:20, width: 10, height: 100))
            path.append(aPath)
        }
        return path
    }
    

    You can use the above view like below, in ViewController

     override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let customView:CustomView = CustomView(frame: CGRect(x: 20, y: 20, width: 300, height: 300))
        self.view.addSubview(customView)
    
    }