ChatGPT解决这个技术问题 Extra ChatGPT

以编程方式创建具有颜色渐变的 UIView

我正在尝试在运行时生成具有渐变色背景(纯色到透明)的视图。有没有办法做到这一点?

这是一个有用的小工具,可以为您创建渐变代码itunes.apple.com/gb/app/gradient-creator/id1031070259?mt=12
使用 CAGradientLayer 创建渐变颜色 appcoda.com/cagradientlayer

C
Community

目标-C:

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
CAGradientLayer *gradient = [CAGradientLayer layer];

gradient.frame = view.bounds;
gradient.colors = @[(id)[UIColor whiteColor].CGColor, (id)[UIColor blackColor].CGColor];

[view.layer insertSublayer:gradient atIndex:0];

迅速:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
let gradient = CAGradientLayer()

gradient.frame = view.bounds
gradient.colors = [UIColor.white.cgColor, UIColor.black.cgColor]

view.layer.insertSublayer(gradient, at: 0)

信息使用 startPoint 和 endPoint 到 change direction of gradient

如果在此 UIView 上添加了任何其他视图(例如 UILabel),您可能需要考虑将这些 UIView 的背景颜色设置为 [UIColor clearColor],以便呈现渐变视图而不是子视图的背景颜色。使用 clearColor 会对性能造成轻微影响。


+1 是所有解决方案中代码量最少的。我刚刚添加到我现有的视图控制器,将 2 refs 更改为 viewself.view,它就像一个魅力:)
同样相关的是添加此代码的位置。我需要以下帖子才能使其正常工作:stackoverflow.com/a/20059268/1480518
这对我帮助很大!在其他地方错过了 CGColor 部分!谢谢
不要忘记使用 'startPoint' 和 'endPoint' 来改变渐变方向。默认值为 (0.5, 0) 和 (0.5,1) - 从上到下方向。
当我的 UIView 使用 AutoLayout 时,我还必须在 viewDidAppear()didRotateFromInterfaceOrientation() 中调用 gradient.frame = view.bounds,否则渐变的大小将无法正确调整。
Y
Yuchen

您可以创建自定义类 GradientView

斯威夫特 5

class GradientView: UIView {
    override open class var layerClass: AnyClass {
       return CAGradientLayer.classForCoder()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let gradientLayer = layer as! CAGradientLayer
        gradientLayer.colors = [UIColor.white.cgColor, UIColor.black.cgColor]
    }
}

在情节提要中,将类类型设置为您想要具有渐变背景的任何视图:

https://i.stack.imgur.com/mAgG0.png

这在以下方面更好:

无需设置 CLayer 的框架

在 UIView 上照常使用 NSConstraint

不需要创建子层(更少的内存使用)


在 Swift 3 上,layerClass 不再是一个函数,它是一个属性,因此您必须像属性一样覆盖它:stackoverflow.com/questions/28786597/…。您还必须实施 override init(frame: CGRect),检查这个答案:stackoverflow.com/questions/27374330/…。谢谢!
您好@LaloLoop,感谢您的评论!我已经更新了代码。我不认为我必须覆盖 init(frame:CGRect)。我测试了更新的代码,它工作正常。
@Yuchen Zhong 它在 IB 中崩溃,但在应用程序中有效。如果使用 @IBDesignable,它没有在 IB 中呈现的任何原因?
@AlexanderVolkov 可能还有其他问题?我们一直在故事板中使用它,但似乎没有任何问题。你可以调试你的故事板,看看哪一行导致它崩溃。
最佳解决方案!
J
Jaywant Khedkar

试试这个它对我来说就像一个魅力,

目标 C

我已将 RGB 渐变背景颜色设置为 UIview

   UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,35)];
   CAGradientLayer *gradient = [CAGradientLayer layer];
   gradient.frame = view.bounds;
   gradient.startPoint = CGPointZero;
   gradient.endPoint = CGPointMake(1, 1);
   gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:34.0/255.0 green:211/255.0 blue:198/255.0 alpha:1.0] CGColor],(id)[[UIColor colorWithRed:145/255.0 green:72.0/255.0 blue:203/255.0 alpha:1.0] CGColor], nil];
   [view.layer addSublayer:gradient];

https://i.stack.imgur.com/dmWrH.png

更新:- Swift3 +

代码 :-

 var gradientView = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 35))
 let gradientLayer:CAGradientLayer = CAGradientLayer()
 gradientLayer.frame.size = self.gradientView.frame.size
 gradientLayer.colors = 
 [UIColor.white.cgColor,UIColor.red.withAlphaComponent(1).cgColor] 
//Use diffrent colors
 gradientView.layer.addSublayer(gradientLayer)

https://i.stack.imgur.com/g33TQ.png

您可以添加渐变颜色的起点和终点。

  gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
  gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)

https://i.stack.imgur.com/2diim.png

有关详细说明,请参阅 CAGradientLayer Doc

希望这对某人有帮助。


S
Sam Fischer

这是我推荐的方法。

为了提高可重用性,我会说创建一个 CAGradientLayer 类别并将所需的渐变添加为类方法。在 header 文件中指定它们,如下所示:

#import <QuartzCore/QuartzCore.h>

@interface CAGradientLayer (SJSGradients)

+ (CAGradientLayer *)redGradientLayer;
+ (CAGradientLayer *)blueGradientLayer;
+ (CAGradientLayer *)turquoiseGradientLayer;
+ (CAGradientLayer *)flavescentGradientLayer;
+ (CAGradientLayer *)whiteGradientLayer;
+ (CAGradientLayer *)chocolateGradientLayer;
+ (CAGradientLayer *)tangerineGradientLayer;
+ (CAGradientLayer *)pastelBlueGradientLayer;
+ (CAGradientLayer *)yellowGradientLayer;
+ (CAGradientLayer *)purpleGradientLayer;
+ (CAGradientLayer *)greenGradientLayer;

@end

然后在您的实现文件中,使用以下语法指定每个渐变:

+ (CAGradientLayer *)flavescentGradientLayer
{
    UIColor *topColor = [UIColor colorWithRed:1 green:0.92 blue:0.56 alpha:1];
    UIColor *bottomColor = [UIColor colorWithRed:0.18 green:0.18 blue:0.18 alpha:1];

    NSArray *gradientColors = [NSArray arrayWithObjects:(id)topColor.CGColor, (id)bottomColor.CGColor, nil];
    NSArray *gradientLocations = [NSArray arrayWithObjects:[NSNumber numberWithInt:0.0],[NSNumber numberWithInt:1.0], nil];

    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.colors = gradientColors;
    gradientLayer.locations = gradientLocations;

    return gradientLayer;
}

然后只需将此类别导入您的 ViewController 或任何其他必需的 subclass,并像这样使用它:

CAGradientLayer *backgroundLayer = [CAGradientLayer purpleGradientLayer];
backgroundLayer.frame = self.view.frame;
[self.view.layer insertSublayer:backgroundLayer atIndex:0];

你应该把代码放在哪里使用它?什么生命周期方法? viewdidappear 让它出现一秒钟太晚了。 viewdidload 和 viewdidappear 导致它在旋转时不起作用。 viewdidlayoutsubviews 更适合旋转,但最终看起来还是有点不稳定。
我个人把它放在viewDidLoad
当我将它放入 viewDidLoad 时,如果应用程序以横向启动,它就不起作用。我的解决方案是使背景层框架比 view.frame 更宽,以补偿其他方向。
viewDidLoad 工作,你只需要设置 AutoResizingMask 使用 [backgroundLayer setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
E
Elijah
extension UIView {

    func applyGradient(isVertical: Bool, colorArray: [UIColor]) { 
        layer.sublayers?.filter({ $0 is CAGradientLayer }).forEach({ $0.removeFromSuperlayer() })
         
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = colorArray.map({ $0.cgColor })
        if isVertical {
            //top to bottom
            gradientLayer.locations = [0.0, 1.0]
        } else {
            //left to right
            gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        }
        
        backgroundColor = .clear
        gradientLayer.frame = bounds
        layer.insertSublayer(gradientLayer, at: 0)
    }

}

用法

someView.applyGradient(isVertical: true, colorArray: [.green, .blue])

b
blauzahn

由于我在整个应用程序中只需要一种渐变,我创建了 UIView 的一个子类,并在初始化时使用固定颜色预配置了渐变层。 UIView 的初始化器调用 configureGradientLayer 方法,该方法配置 CAGradientLayer:

DDGradientView.h:

#import <UIKit/UIKit.h>

@interface DDGradientView : UIView {

}
@end

DDGradientView.m:

#import "DDGradientView.h"

@implementation DDGradientView

// Change the views layer class to CAGradientLayer class
+ (Class)layerClass
{
    return [CAGradientLayer class];
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if(self) {
        [self configureGradientLayer];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if(self) {
        [self configureGradientLayer];
    }
    return self;
}

// Make custom configuration of your gradient here   
- (void)configureGradientLayer {
    CAGradientLayer *gLayer = (CAGradientLayer *)self.layer;
    gLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor lightGrayColor] CGColor], nil];
}
@end

方法名称initGradientLayer 类似于初始化程序。我觉得不是很合适。
@DawnSong 好点,我将其更改为“configureGradientLayer”。
f
flocbit

我使用 Swift 的扩展功能和枚举稍微扩展了已接受的答案。

哦,如果您像我一样使用 Storyboard,请务必在 viewDidLayoutSubviews() 或稍后调用 gradientBackground(from:to:direction:)

斯威夫特 3

enum GradientDirection {
    case leftToRight
    case rightToLeft
    case topToBottom
    case bottomToTop
}

extension UIView {
    func gradientBackground(from color1: UIColor, to color2: UIColor, direction: GradientDirection) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = [color1.cgColor, color2.cgColor]

        switch direction {
        case .leftToRight:
            gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
        case .rightToLeft:
            gradient.startPoint = CGPoint(x: 1.0, y: 0.5)
            gradient.endPoint = CGPoint(x: 0.0, y: 0.5)
        case .bottomToTop:
            gradient.startPoint = CGPoint(x: 0.5, y: 1.0)
            gradient.endPoint = CGPoint(x: 0.5, y: 0.0)
        default:
            break
        }

        self.layer.insertSublayer(gradient, at: 0)
    }
}

这适用于每个解决方案,但只是提醒 self.clipsToBounds 需要为 true 或 gradient.cornerRadius 需要设置为 self.layer.cornerRadius 如果 self 有圆角。
D
Dustin Williams

快速实施:

var gradientLayerView: UIView = UIView(frame: CGRectMake(0, 0, view.bounds.width, 50))
var gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = gradientLayerView.bounds
gradient.colors = [UIColor.grayColor().CGColor, UIColor.clearColor().CGColor]
gradientLayerView.layer.insertSublayer(gradient, atIndex: 0)
self.view.layer.insertSublayer(gradientLayerView.layer, atIndex: 0)

G
Guillaume Legrain

我已经通过扩展迅速实现了这一点:

斯威夫特 3

extension UIView {
    func addGradientWithColor(color: UIColor) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = [UIColor.clear.cgColor, color.cgColor]

        self.layer.insertSublayer(gradient, at: 0)
    }
}

斯威夫特 2.2

extension UIView {
    func addGradientWithColor(color: UIColor) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = [UIColor.clearColor().CGColor, color.CGColor]

        self.layer.insertSublayer(gradient, atIndex: 0)
    }
}

不,我可以像这样在每个视图上设置渐变:

myImageView.addGradientWithColor(UIColor.blue)

Swift3 调用必须是这样的: myImageView.addGradientWithColor(color: UIColor.blue)
E
Etienne Noël

一种快速的方法

该答案建立在上述答案的基础上,并提供了用于处理在旋转期间未正确应用梯度的问题的实现。它通过将渐变层更改为正方形来解决这个问题,以便在所有方向上旋转都会产生正确的渐变。函数签名包括一个 Swift 可变参数,它允许根据需要传入尽可能多的 CGColorRef (CGColor)(参见示例用法)。还提供了一个作为 Swift 扩展的示例,以便可以将渐变应用到任何 UIView。

   func configureGradientBackground(colors:CGColorRef...){

        let gradient: CAGradientLayer = CAGradientLayer()
        let maxWidth = max(self.view.bounds.size.height,self.view.bounds.size.width)
        let squareFrame = CGRect(origin: self.view.bounds.origin, size: CGSizeMake(maxWidth, maxWidth))
        gradient.frame = squareFrame

        gradient.colors = colors
        view.layer.insertSublayer(gradient, atIndex: 0)
    }

要使用:

在 viewDidLoad...

  override func viewDidLoad() {
        super.viewDidLoad()
        configureGradientBackground(UIColor.redColor().CGColor, UIColor.whiteColor().CGColor)
  }

扩展实施

extension CALayer {


    func configureGradientBackground(colors:CGColorRef...){

        let gradient = CAGradientLayer()

        let maxWidth = max(self.bounds.size.height,self.bounds.size.width)
        let squareFrame = CGRect(origin: self.bounds.origin, size: CGSizeMake(maxWidth, maxWidth))
        gradient.frame = squareFrame

        gradient.colors = colors

        self.insertSublayer(gradient, atIndex: 0)
    }

}

扩展用例示例:

 override func viewDidLoad() {
        super.viewDidLoad()

        self.view.layer.configureGradientBackground(UIColor.purpleColor().CGColor, UIColor.blueColor().CGColor, UIColor.whiteColor().CGColor)
 }

这意味着渐变背景现在可以应用于任何 UIControl,因为所有控件都是 UIView(或子类)并且所有 UIView 都有 CALayers。

斯威夫特 4

扩展实施

extension CALayer {
    public func configureGradientBackground(_ colors:CGColor...){

        let gradient = CAGradientLayer()

        let maxWidth = max(self.bounds.size.height,self.bounds.size.width)
        let squareFrame = CGRect(origin: self.bounds.origin, size: CGSize(width: maxWidth, height: maxWidth))
        gradient.frame = squareFrame

        gradient.colors = colors

        self.insertSublayer(gradient, at: 0)
    }    
}

扩展用例示例:

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.layer.configureGradientBackground(UIColor.purple.cgColor, UIColor.blue.cgColor, UIColor.white.cgColor)
}

K
Kendall Helmstetter Gelner

您正在寻找的是 CAGradientLayer。每个 UIView 都有一个层 - 您可以在该层中添加子层,就像您可以添加子视图一样。一种特定类型是 CAGradientLayer,您可以在其中为其提供一组颜色以进行渐变。

一个示例是渐变视图的简单包装器:

http://oleb.net/blog/2010/04/obgradientview-a-simple-uiview-wrapper-for-cagradientlayer/

请注意,您需要包含 QuartZCore 框架才能访问 UIView 的所有层部分。


A
Alexander Volkov

斯威夫特 4:

在 IB 中正确显示梯度:

@IBDesignable public class GradientView: UIView {

    override open class var layerClass: AnyClass {
        return CAGradientLayer.classForCoder()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        configureGradientLayer()
    }

    public override init(frame: CGRect) {
        super.init(frame: frame)
        configureGradientLayer()
    }

    func configureGradientLayer() {
        let gradientLayer = layer as! CAGradientLayer
        gradientLayer.colors = [UIColor(hex: 0x003399).cgColor, UIColor(hex: 0x00297b).cgColor]
    }
}

d
dulgan

基于雨辰版本的简单swift视图

class GradientView: UIView {
    override class func layerClass() -> AnyClass { return CAGradientLayer.self }

    lazy var gradientLayer: CAGradientLayer = {
        return self.layer as! CAGradientLayer
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

}

然后你可以像这样初始化后使用gradientLayer ...

someView.gradientLayer.colors = [UIColor.whiteColor().CGColor, UIColor.blackColor().CGColor]

R
Ronaldo Albertini

调用上面的解决方案来更新图层是一个好主意

viewDidLayoutSubviews 

正确更新视图


T
Timur Bernikovich

我的解决方案是创建 UIView 子类,其中 CAGradientLayer 可作为只读属性访问。这将允许您根据需要自定义渐变,并且您不需要自己处理布局更改。子类实现:

@interface GradientView : UIView

@property (nonatomic, readonly) CAGradientLayer *gradientLayer;

@end

@implementation GradientView

+ (Class)layerClass
{
    return [CAGradientLayer class];
}

- (CAGradientLayer *)gradientLayer
{
    return (CAGradientLayer *)self.layer;
}

@end

用法:

self.iconBackground = [GradientView new];
[self.background addSubview:self.iconBackground];
self.iconBackground.gradientLayer.colors = @[(id)[UIColor blackColor].CGColor, (id)[UIColor whiteColor].CGColor];
self.iconBackground.gradientLayer.startPoint = CGPointMake(1.0f, 1.0f);
self.iconBackground.gradientLayer.endPoint = CGPointMake(0.0f, 0.0f);

A
Azharhussain Shaikh

斯威夫特 3

在视图上添加渐变层

绑定您的视图出口@IBOutlet var YOURVIEW:UIView!

定义 CAGradientLayer() var gradient = CAGradientLayer()

这是您必须在 viewDidLoad YOURVIEW.layoutIfNeeded() 中编写的代码 gradient.startPoint = CGPoint(x: CGFloat(0), y: CGFloat(1)) gradient.endPoint = CGPoint(x: CGFloat(1), y : CGFloat(0)) gradient.frame = YOURVIEW.bounds gradient.colors = [UIColor.red.cgColor, UIColor.green.cgColor] gradient.colors = [ UIColor(red: 255.0/255.0, green: 56.0/255.0, blue : 224.0/255.0, alpha: 1.0).cgColor,UIColor(red: 86.0/255.0, green: 13.0/255.0, blue: 232.0/255.0, alpha: 1.0).cgColor,UIColor(red: 16.0/255.0, green: 173.0 /255.0, blue: 245.0/255.0, alpha: 1.0).cgColor] gradient.locations = [0.0 ,0.6 ,1.0] YOURVIEW.layer.insertSublayer(gradient, at: 0)


我使用了这种方法,将“topview”更改为我的 IBoutlet 的名称以供查看。我删除了“SearchView”行。
好计划 - 也许还请注意,您可以使用任何一个 gradient.colors 设置。因此,如果您使用命名的 UI 颜色注释掉简单的 gradient.colors,图像是相同的,但是如果您注释掉另一个,颜色渐变则依赖于红色到绿色。用户可以做任何一个。
i
iCyberPaul

在 Swift 3.1 中,我已将此扩展添加到 UIView

import Foundation
import UIKit
import CoreGraphics


extension UIView {
    func gradientOfView(withColours: UIColor...) {

        var cgColours = [CGColor]()

        for colour in withColours {
            cgColours.append(colour.cgColor)
        }
        let grad = CAGradientLayer()
        grad.frame = self.bounds
        grad.colors = cgColours
        self.layer.insertSublayer(grad, at: 0)
    }
}

然后我打电话给

    class OverviewVC: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

            self.view.gradientOfView(withColours: UIColor.red,UIColor.green, UIColor.blue)

        }
}

P
Padmaja

我已经在我的代码中实现了这一点。

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 31.0f)];
view1.backgroundColor = [UIColor clearColor];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view1.bounds;
UIColor *topColor = [UIColor colorWithRed:132.0/255.0 green:222.0/255.0 blue:109.0/255.0 alpha:1.0];
UIColor *bottomColor = [UIColor colorWithRed:31.0/255.0 green:150.0/255.0 blue:99.0/255.0 alpha:1.0];
gradient.colors = [NSArray arrayWithObjects:(id)[topColor CGColor], (id)[bottomColor CGColor], nil];


[view1.layer insertSublayer:gradient atIndex:0];

现在我可以在视图中看到渐变。


H
Hardik Thakkar

为 UIView 提供渐变颜色(swift 4.2)

func makeGradientLayer(`for` object : UIView, startPoint : CGPoint, endPoint : CGPoint, gradientColors : [Any]) -> CAGradientLayer {
        let gradient: CAGradientLayer = CAGradientLayer()
        gradient.colors = gradientColors
        gradient.locations = [0.0 , 1.0]
        gradient.startPoint = startPoint
        gradient.endPoint = endPoint
        gradient.frame = CGRect(x: 0, y: 0, w: object.frame.size.width, h: object.frame.size.height)
        return gradient
    }

如何使用

let start : CGPoint = CGPoint(x: 0.0, y: 1.0)
let end : CGPoint = CGPoint(x: 1.0, y: 1.0)

let gradient: CAGradientLayer = makeGradientLayer(for: cell, startPoint: start, endPoint: end, gradientColors: [
                    UIColor(red:0.92, green:0.07, blue:0.4, alpha:1).cgColor,
                    UIColor(red:0.93, green:0.11, blue:0.14, alpha:1).cgColor
                    ])

self.vwTemp.layer.insertSublayer(gradient, at: 0)

W
Wo_0NDeR ᵀᴹ

此框架适用于 Historyboard 中的渐变和其他 UI 修改:Design and prototype customized UI, interaction, navigation, transition and animation for App Store ready Apps in Interface Builder with IBAnimatable.

有了这个,您可以选择一个视图,将类设置为 AnimatableView,并从 Interface Builder 属性设置渐变和实时预览结果。

请参阅 this 了解如何将渐变应用到 UIView。