3/15/15

iOS Gradient View with Clipped Path

Custom gradient view with support for 3 shapes: default, circle, circle-outline.
Copy path with CGPathCreateCopyByStrokingPath, clip, then draw gradient.




//swift

import UIKit

class ViewController: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()

        var gv = [ESGradientView]()
        var x = 100
        for i in 0...5
        {
            var g = ESGradientView()
            g.frame = CGRect(x:x, y:200, width:100, height:100)
            g.gradientColors = i < 3 ? g.gradientColors : [UIColor.redColor().CGColor, UIColor.blackColor().CGColor]
            gv.append(g)
            self.view.addSubview(g)
            x += 110
        }

        gv[1].shape = .Circle
        gv[2].shape = .CircleOutline
        gv[4].shape = .Circle
        gv[5].shape = .CircleOutline
        gv[5].circleOutlineWidth = 1
    }
}


class ESGradientView: UIView
{

    enum Shape
    {
        case Default, Circle, CircleOutline
    }

    var shape = Shape.Default
    var circleOutlineWidth:Int = 4
    var gradientColors = [UIColor.redColor().CGColor, UIColor.blueColor().CGColor]
    var gradientLocations:[CGFloat] = [0, 1]
    var gradientEndOffset:CGFloat = 20


    override func drawRect(rect: CGRect)
    {
        var context = UIGraphicsGetCurrentContext()

        if (shape == .Circle)
        {
            let path = getCirclePath(1)
            path.addClip()
        }
        else if (shape == .CircleOutline)
        {
            let path = getCirclePath(circleOutlineWidth + 2)
            var pathRef = CGPathCreateCopyByStrokingPath(path.CGPath, nil, CGFloat(circleOutlineWidth), kCGLineCapRound, kCGLineJoinRound, 1)
            UIBezierPath(CGPath: pathRef).addClip()
        }

        var gradient = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), gradientColors, gradientLocations)
        let gradientEndPoint = CGPointMake(bounds.width - gradientEndOffset, bounds.height - gradientEndOffset)
        CGContextDrawLinearGradient(context, gradient!, CGPointZero, gradientEndPoint, UInt32(kCGGradientDrawsAfterEndLocation))
    }   

    func getCirclePath(inset:Int) -> UIBezierPath
    {
        let center = CGFloat(bounds.width * 0.5)
        let radius = CGFloat(center * CGFloat(100 - inset) * 0.01)
        let centerPoint = CGPointMake(center, center)
        var cp = UIBezierPath(arcCenter:centerPoint, radius:radius, startAngle:0, endAngle:CGFloat(M_PI * 2), clockwise:true)

        return cp
    }
}

No comments:

Post a Comment