【问题标题】:how to make a gradient border of UIView?如何制作 UIView 的渐变边框?
【发布时间】:2013-03-04 03:12:52
【问题描述】:

我想做一个如下图的渐变边框:

但我不知道它到底是怎么做的,即我应该使用什么渐变颜色来做到这一点?如何设置我的视图以显示像图像一样的边框?

我正在使用以下代码来获取边框:

 self.view.layer.borderColor = [UIColor orangeColor].CGColor;
 self.view.layer.borderWidth = 2.0f;

【问题讨论】:

标签: ios border gradient


【解决方案1】:

这就是我所做的,而且效果很好

   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)
    }

}

【讨论】:

  • 我注意到颜色参数是一个 UIColor 数组,但默认值是一个 CGColor 数组。不过答案很好:)
  • 嗯,这已经过时了
【解决方案2】:

感谢 Tiago Mendes 的回答。

我改进了功能:

  • 添加圆角半径。

并修复了一些问题以确保正确的遮罩和给定的边框宽度:

  • 改进的渐变层框架;
  • 改进的蒙版路径圆角矩形。

斯威夫特 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
    }
}

对于渐变层的startPointendPoint 的更易读声明,我使用以下代码:

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)
        }
    }
}

所以最终的用法是:

view.gradientBorder(width: 3, colors: [.red, .orange], startPoint: .unitCoordinate(.top), endPoint: .unitCoordinate(.bottom), andRoundCornersWithRadius: 12)

【讨论】:

  • 太棒了!谢谢你。它允许我为屏幕制作边框并修复 iphone x 的半径角。 +1 !
  • 对于出色的解决方案,只需为 iPhone X 系列 +1 设置圆角半径 40
  • 很高兴为您提供帮助!实际上,如果你想要 iphone X 系列屏幕的圆角半径,你应该看看另一种绘制贝塞尔路径的方法 - apple.stackexchange.com/questions/313713/…
  • 如何使 UIButton 工作?理想情况下,它应该适用于 UIView 的任何子类,但不适用于 UIButton。我只是在左上角看到一个点。 @eli7ah
  • 非常酷!赞成。问题:我们如何扩展它以支持外部边界? (向外而不是向内增长的边界)
【解决方案3】:

你可以使用这个来制作视图的渐变边框和圆角半径(如果你愿意的话)——

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];

这将对您有所帮助!谢谢

【讨论】:

  • 这个解决方案几乎对我有用,但是在圆角处边框被切断了。知道如何确保边框绕过角落吗?
  • 使用方法[UIBezierPath bezierPathWithRoundedRect:self.layer.bounds cornerRadius:<radius>].CGPath得到它我将它设置为UIView上的类扩展方法,因此self.layer.bounds
【解决方案4】:

这是另一个适用于 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
    }

}

使用方法:

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

【讨论】:

    【解决方案5】:

    以下是使用 Core Graphics 的方法。创建一个 UIView 子类并在其drawRect: 创建一个渐变并用黑色内容矩形覆盖它:

    - (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);
    }
    

    这将产生与您想要达到的结果相似的结果。

    【讨论】:

    • 不同方法的比较给了我们很多思考。
    【解决方案6】:

    Christos Hadjikyriacou 回答的objective-c 版本

      @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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-09
      • 1970-01-01
      • 2019-05-23
      • 2020-07-25
      • 1970-01-01
      相关资源
      最近更新 更多