how to make a gradient border of UIView?

后端 未结 6 1104
遇见更好的自我
遇见更好的自我 2020-12-28 17:37

I want to make a gradient border of view like the following picture:

\"Image\"

but I don\'t know how d

相关标签:
6条回答
  • 2020-12-28 18:17

    Here is how you would do it with Core Graphics. Create a UIView subclass and in its drawRect: create a gradient and overlay that with a black content rectangle:

    - (void)drawRect:(CGRect)rect
    {
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
        // Create and draw the gradient
        UIColor *gradientColorTop = [UIColor orangeColor];
        UIColor *gradientColorBottom = [UIColor yellowColor];
        NSArray *gradientColors = @[(id) gradientColorTop.CGColor, (id) gradientColorBottom.CGColor];
        CGFloat locations[] = {0.1, 0.80};
    
        CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)(gradientColors), locations);
    
        CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
        CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
    
        UIBezierPath *gradientBorder = [UIBezierPath bezierPathWithRoundedRect:rect
        byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(10.0, 10.0)];
        [gradientBorder addClip];
    
        CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0);
    
        // Draw the inner content rectangle
        UIBezierPath *contentPath = [UIBezierPath bezierPathWithRect:CGRectInset(rect, 20.0, 20.0)];
        [[UIColor blackColor] setFill];
        [contentPath fill];
    
        CGGradientRelease(gradient);
        CGColorSpaceRelease(colorSpace);
    }
    

    That would produce a result similar to what you are trying to achieve.

    0 讨论(0)
  • 2020-12-28 18:17

    Here is another solution that is working on swift 4

    import UIKit
    
    public extension UIView {
    
        private static let kLayerNameGradientBorder = "GradientBorderLayer"
    
        func setGradientBorder(
            width: CGFloat,
            colors: [UIColor],
            startPoint: CGPoint = CGPoint(x: 0.5, y: 0),
            endPoint: CGPoint = CGPoint(x: 0.5, y: 1)
        ) {
            let existedBorder = gradientBorderLayer()
            let border = existedBorder ?? CAGradientLayer()
            border.frame = bounds
            border.colors = colors.map { return $0.cgColor }
            border.startPoint = startPoint
            border.endPoint = endPoint
    
            let mask = CAShapeLayer()
            mask.path = UIBezierPath(roundedRect: bounds, cornerRadius: 0).cgPath
            mask.fillColor = UIColor.clear.cgColor
            mask.strokeColor = UIColor.white.cgColor
            mask.lineWidth = width
    
            border.mask = mask
    
            let exists = existedBorder != nil
            if !exists {
                layer.addSublayer(border)
            }
        }
    
    
        private func gradientBorderLayer() -> CAGradientLayer? {
            let borderLayers = layer.sublayers?.filter { return $0.name == UIView.kLayerNameGradientBorder }
            if borderLayers?.count ?? 0 > 1 {
                fatalError()
            }
            return borderLayers?.first as? CAGradientLayer
        }
    
    }
    

    How to use:

    view.setGradientBorder(width: 10, colors: [UIColor(red: 47, green: 198, blue: 176), UIColor(red: 67, green: 210, blue: 128)])

    0 讨论(0)
  • 2020-12-28 18:19

    You can make gradient border of view and corner radius(if you want) using this--

    self.yourView.layer.cornerRadius=4;
    
    self.yourView.layer.masksToBounds=YES;
    
    CAGradientLayer *gradient = [CAGradientLayer layer];
    
    gradient.frame = self.yourView.bounds;
    
    gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:255/255.0 green:226/255.0 blue:138/255.0 alpha:1.0] CGColor], (id)[[UIColor colorWithRed:255/255.0 green:198/255.0 blue:91/255.0 alpha:0.9] CGColor],(id)[[UIColor colorWithRed:255/255.0 green:226/255.0 blue:138/255.0 alpha:1.0] CGColor], nil];
    
    gradient.startPoint = CGPointMake(0.0, 0.0);
    
    gradient.endPoint = CGPointMake(1, 1);
    
    CAShapeLayer *shapeLayer =[[CAShapeLayer alloc] init];
    
    shapeLayer.lineWidth = 15; // higher number higher border width
    
    shapeLayer.path = [UIBezierPath bezierPathWithRect:self.yourView.bounds].CGPath;
    
    shapeLayer.fillColor = nil;
    
    shapeLayer.strokeColor = [UIColor blackColor].CGColor;
    
    gradient.mask = shapeLayer;
    
    [self.yourView.layer insertSublayer:gradient atIndex:0];
    

    this will help you! Thanks

    0 讨论(0)
  • 2020-12-28 18:21

    objective-c version of Christos Hadjikyriacou's answer

      @implementation CALayer(Border)
    
    -(void) addGradientBorder {
    
    CAGradientLayer *gradientLayer =  [[CAGradientLayer alloc] init];
    gradientLayer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
    gradientLayer.startPoint = CGPointMake(0.0, 0.5);
    gradientLayer.endPoint = CGPointMake(1.0, 0.5);
    gradientLayer.colors = @[(id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor];
    
    CAShapeLayer *shapeLayer =[[CAShapeLayer alloc] init];
    shapeLayer.lineWidth = 0.5;
    shapeLayer.path = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
    shapeLayer.fillColor = nil;
    shapeLayer.strokeColor = [UIColor blackColor].CGColor;
    gradientLayer.mask = shapeLayer;
    [self addSublayer : gradientLayer];
    }
    @end
    
    0 讨论(0)
  • 2020-12-28 18:26

    Thanx Tiago Mendes for answer.

    I improved functionality:

    • added corner radius.

    And fixed some issues to ensure correct masking and given border width:

    • improved gradient layer frame;
    • improved mask path rounding rect.

    Swift 5

    public extension UIView {
    
        private static let kLayerNameGradientBorder = "GradientBorderLayer"
    
        func gradientBorder(width: CGFloat,
                            colors: [UIColor],
                            startPoint: CGPoint = CGPoint(x: 0.5, y: 0.0),
                            endPoint: CGPoint = CGPoint(x: 0.5, y: 1.0),
                            andRoundCornersWithRadius cornerRadius: CGFloat = 0) {
    
            let existingBorder = gradientBorderLayer()
            let border = existingBorder ?? CAGradientLayer()
            border.frame = CGRect(x: bounds.origin.x, y: bounds.origin.y,
                                  width: bounds.size.width + width, height: bounds.size.height + width)
            border.colors = colors.map { return $0.cgColor }
            border.startPoint = startPoint
            border.endPoint = endPoint
    
            let mask = CAShapeLayer()
            let maskRect = CGRect(x: bounds.origin.x + width/2, y: bounds.origin.y + width/2,
                                  width: bounds.size.width - width, height: bounds.size.height - width)
            mask.path = UIBezierPath(roundedRect: maskRect, cornerRadius: cornerRadius).cgPath
            mask.fillColor = UIColor.clear.cgColor
            mask.strokeColor = UIColor.white.cgColor
            mask.lineWidth = width
    
            border.mask = mask
    
            let exists = (existingBorder != nil)
            if !exists {
                layer.addSublayer(border)
            }
        }
        private func gradientBorderLayer() -> CAGradientLayer? {
            let borderLayers = layer.sublayers?.filter { return $0.name == UIView.kLayerNameGradientBorder }
            if borderLayers?.count ?? 0 > 1 {
                fatalError()
            }
            return borderLayers?.first as? CAGradientLayer
        }
    }
    

    And for more readable declaration of startPoint and endPoint of gradient layer I use this code:

    public extension CGPoint {
    
        enum CoordinateSide {
            case topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
        }
    
        static func unitCoordinate(_ side: CoordinateSide) -> CGPoint {
            switch side {
            case .topLeft:      return CGPoint(x: 0.0, y: 0.0)
            case .top:          return CGPoint(x: 0.5, y: 0.0)
            case .topRight:     return CGPoint(x: 1.0, y: 0.0)
            case .right:        return CGPoint(x: 0.0, y: 0.5)
            case .bottomRight:  return CGPoint(x: 1.0, y: 1.0)
            case .bottom:       return CGPoint(x: 0.5, y: 1.0)
            case .bottomLeft:   return CGPoint(x: 0.0, y: 1.0)
            case .left:         return CGPoint(x: 1.0, y: 0.5)
            }
        }
    }
    

    So final usage is:

    view.gradientBorder(width: 3, colors: [.red, .orange], startPoint: .unitCoordinate(.top), endPoint: .unitCoordinate(.bottom), andRoundCornersWithRadius: 12)
    
    0 讨论(0)
  • 2020-12-28 18:41

    This what i did and it worked perfectly

       extension CALayer {
        func addGradienBorder(colors:[UIColor],width:CGFloat = 1) {
            let gradientLayer = CAGradientLayer()
            gradientLayer.frame =  CGRect(origin: CGPointZero, size: self.bounds.size)
            gradientLayer.startPoint = CGPointMake(0.0, 0.5)
            gradientLayer.endPoint = CGPointMake(1.0, 0.5)
            gradientLayer.colors = colors.map({$0.CGColor})
    
            let shapeLayer = CAShapeLayer()
            shapeLayer.lineWidth = width
            shapeLayer.path = UIBezierPath(rect: self.bounds).CGPath
            shapeLayer.fillColor = nil
            shapeLayer.strokeColor = UIColor.blackColor().CGColor
            gradientLayer.mask = shapeLayer
    
            self.addSublayer(gradientLayer)
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题