4

Hi I would like to create a button similar to (attached) image.

enter image description here

challenge here is round corner with gradient color. I was able to create round corner using

view.layer setCornerRadius:radius; view.layer setMasksToBounds:YES;

I am also able to create single border color

view.layer.borderColor = color.CGColor; view.layer.borderWidth = width;

But what need to be done for gradient border color?

I did following but it is not as desired. I followed this post but it does not provide me gradient border color. UIButton w/ gradient, rounded corners, border, and drop shadow

Can anyone help me understand, how can i draw gradient border for UIButton. Pseudo code/Example will be very helpful.

Community
  • 1
  • 1
iamMobile
  • 959
  • 2
  • 17
  • 35
  • If you're wanting a linear gradient around the edge of the button you could try turning the line into a hollow polygon and then filling that with a radial gradient. Otherwise, your simplest approach, is quite probably to draw the button background in Photoshop or the image manipulation package of your choice and just use it for the button background. – David Berry Aug 18 '15 at 05:12

2 Answers2

6

This applies a linear gradient to the line around a round rect by creating a polygon round rect with a hole cut in the middle and then using that to clip a fill of the linear gradient.

class DisplayView : UIView {
    override func drawRect(var rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()

        CGContextSaveGState(context)

        // Inset the rect so we can stroke it and not be outside the button bounds
        rect = CGRectInset(rect, 4.0, 4.0)

        // Construct the the bounds
        var path = CGPathCreateWithRoundedRect(rect, rect.size.height / 2, rect.size.height / 2, nil)

        // Fill the middle with white (or other background color
        CGContextAddPath(context, path)
        CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
        CGContextFillPath(context)

        // stroke the path
        path = CGPathCreateCopyByStrokingPath(path, nil, 4.0, kCGLineCapButt, kCGLineJoinBevel, 0)

        // Add the outer edge of the button frame
        CGContextAddPath(context, path)

        // Create a gradient from white to red
        let colors = [
            UIColor.yellowColor().CGColor,
            UIColor.redColor().CGColor
        ]

        // Set the round rect as the clip
        CGContextClip(context)

        // Fill the path with the radial gradient
        let baseSpace = CGColorSpaceCreateDeviceRGB();
        let gradient = CGGradientCreateWithColors(baseSpace, colors, nil);

        CGContextDrawLinearGradient(
            context,
            gradient,
            CGPoint(x:0, y:0),
            CGPoint(x:CGRectGetMaxX(rect), y:CGRectGetMaxY(rect)),
            .allZeros)

        // Fill the line
        CGContextFillPath(context)

        CGContextRestoreGState(context)
    }
}

Swift 4

class DisplayView : UIView {
    override func draw(_ rect: CGRect) {
        var rect = rect
        let context = UIGraphicsGetCurrentContext()

        context!.saveGState()

        // Inset the rect so we can stroke it and not be outside the button bounds
        rect = rect.insetBy(dx: 4.0, dy: 4.0)

        // Construct the the bounds
        var path = CGPath(roundedRect: rect,
                          cornerWidth: rect.size.width / 2,
                          cornerHeight: rect.size.height / 2,
                          transform: nil)

        // Fill the middle with white (or other background color
        context!.addPath(path)
        context?.setFillColor(UIColor.clear.cgColor)
        context?.fillPath()

        // stroke the path
        path = path.copy(strokingWithWidth: 4.0,
                         lineCap: CGLineCap.butt,
                         lineJoin: CGLineJoin.bevel,
                         miterLimit: 0)

        // Add the outer edge of the button frame
        context?.addPath(path)

        // Create a gradient from white to red
        let colors = [
            UIColor.yellow.cgColor,
            UIColor.red.cgColor
        ]

        // Set the round rect as the clip
        context?.clip()

        // Fill the path with the radial gradient
        let baseSpace = CGColorSpaceCreateDeviceRGB();
        let gradient = CGGradient(colorsSpace: baseSpace,
                                  colors: colors as CFArray,
                                  locations: nil);

        context?.drawLinearGradient(gradient!,
                                    start: CGPoint(x:0, y:0),
                                    end: CGPoint(x: rect.maxX, y: rect.maxY),
                                    options: CGGradientDrawingOptions())

        // Fill the line
        context?.fillPath()

        context?.restoreGState()
    }
}
Gend
  • 133
  • 3
  • 11
David Berry
  • 40,941
  • 12
  • 84
  • 95
0

Here is how I did it. In my case @loginButton is bound to one from storyboard. Try this, see how it looks like and tune to what you need.

@property (nonatomic, retain) IBOutlet UIButton *loginButton;

- (void) viewDidLoad
{
    [super viewDidLoad];

    CAGradientLayer *gradient = [CAGradientLayer layer];
    loginButton.clipsToBounds = YES;
    UIColor *topColor = [UIColor colorWithRed:255/255 green:255/255 blue:255/255 alpha:0.9];
    UIColor *middleColor = [UIColor colorWithRed:61.0/255 green:130.0/255 blue:244.0/255 alpha:1.0];
    UIColor *bottomColor = [UIColor colorWithRed:24.0/255 green:77.0/255 blue:214.0/255 alpha:1.0];
    gradient.colors = [NSArray arrayWithObjects:(id)topColor.CGColor,
                       (id)middleColor.CGColor, (id)bottomColor.CGColor, nil];
    gradient.locations = [NSArray arrayWithObjects:
                          [NSNumber numberWithFloat:0.0f],
                          [NSNumber numberWithFloat:0.05f],
                          [NSNumber numberWithFloat:0.7],
                          nil];
    gradient.frame = [[loginButton layer] bounds];
    gradient.cornerRadius = 4.0;
    gradient.borderWidth = 0.5;
    [loginButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [loginButton.layer insertSublayer:gradient atIndex:0]; 
    [loginButton addTarget:self action:@selector(loginTouchDown:)
            forControlEvents:UIControlEventTouchDown];
    [loginButton addTarget:self action:@selector(loginTouchUp:)
          forControlEvents:UIControlEventTouchUpOutside];

}
Cynichniy Bandera
  • 5,991
  • 2
  • 29
  • 33
  • Isn't this gradient creating a filled gradient within the button only? The question was to create a bordered gradient instead of filling a gradient within the button – Vinh Mar 23 '16 at 12:05