Ios 在Swift中设置按钮上的背景渐变
我不知道如何在按钮上设置背景渐变(不将背景渐变设置为图像)。这和安卓有很大不同 这里有一个类,我必须定义一个可返回的梯度方案:Ios 在Swift中设置按钮上的背景渐变,ios,swift,button,linear-gradients,Ios,Swift,Button,Linear Gradients,我不知道如何在按钮上设置背景渐变(不将背景渐变设置为图像)。这和安卓有很大不同 这里有一个类,我必须定义一个可返回的梯度方案: import UIKit extension CAGradientLayer { func backgroundGradientColor() -> CAGradientLayer { let topColor = UIColor(red: (0/255.0), green: (153/255.0), blue:(51/255.0),
import UIKit
extension CAGradientLayer {
func backgroundGradientColor() -> CAGradientLayer {
let topColor = UIColor(red: (0/255.0), green: (153/255.0), blue:(51/255.0), alpha: 1)
let bottomColor = UIColor(red: (0/255.0), green: (153/255.0), blue:(255/255.0), alpha: 1)
let gradientColors: [CGColor] = [topColor.CGColor, bottomColor.CGColor]
let gradientLocations: [Float] = [0.0, 1.0]
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations
return gradientLayer
}
}
我可以使用此选项设置整个视图的背景,如下所示:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let background = CAGradientLayer().backgroundGradientColor()
background.frame = self.view.bounds
self.view.layer.insertSublayer(background, atIndex: 0)
}
//...
}
但是如何访问按钮的视图并插入子层或类似的内容呢?您的代码工作正常。您只需记住每次设置渐变的帧。最好只是使渐变类别也为您设置视图的框架 这样你就不会忘记,而且适用性很好
import UIKit
extension UIView {
@discardableResult
func applyGradient(colours: [UIColor]) -> CAGradientLayer {
return self.applyGradient(colours: colours, locations: nil)
}
@discardableResult
func applyGradient(colours: [UIColor], locations: [NSNumber]?) -> CAGradientLayer {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.locations = locations
self.layer.insertSublayer(gradient, at: 0)
return gradient
}
}
class ViewController: UIViewController {
@IBOutlet weak var btn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.btn.applyGradient(colours: [.yellow, .blue])
self.view.applyGradient(colours: [.yellow, .blue, .red], locations: [0.0, 0.5, 1.0])
}
}
按钮是视图。将渐变应用于该视图的方式与将其应用于任何其他视图的方式相同
图片校对:
视频校对:
在下面,您可以找到Swift3(以及Swift4)和稍微扩展的解决方案(方向助手):
@Zeb的回答很好,但只是为了把它清理干净,让它更快一点。 计算的只读属性应避免使用get,返回的Void是多余的:
typealias GradientPoints = (startPoint: CGPoint, endPoint: CGPoint)
enum GradientOrientation {
case topRightBottomLeft
case topLeftBottomRight
case horizontal
case vertical
var startPoint: CGPoint {
return points.startPoint
}
var endPoint: CGPoint {
return points.endPoint
}
var points: GradientPoints {
switch self {
case .topRightBottomLeft:
return (CGPoint(x: 0.0, y: 1.0), CGPoint(x: 1.0, y: 0.0))
case .topLeftBottomRight:
return (CGPoint(x: 0.0, y: 0.0), CGPoint(x: 1, y: 1))
case .horizontal:
return (CGPoint(x: 0.0, y: 0.5), CGPoint(x: 1.0, y: 0.5))
case .vertical:
return (CGPoint(x: 0.0, y: 0.0), CGPoint(x: 0.0, y: 1.0))
}
}
}
extension UIView {
func applyGradient(withColours colours: [UIColor], locations: [NSNumber]? = nil) {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.locations = locations
self.layer.insertSublayer(gradient, at: 0)
}
func applyGradient(withColours colours: [UIColor], gradientOrientation orientation: GradientOrientation) {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.startPoint = orientation.startPoint
gradient.endPoint = orientation.endPoint
self.layer.insertSublayer(gradient, at: 0)
}
}
我都试过了这是我在viewdidload里面的按钮init
let button = UIButton()
button.setTitle("Alper", for: .normal)
button.layer.borderColor = UIColor.white.cgColor
button.layer.borderWidth = 1
view.addSubview(button)
button.anchor(top: nil, left: nil, bottom: logo.topAnchor, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, height: 50, width: 100)
let gradientx = CAGradientLayer()
gradientx.colors = [UIColor.blue,UIColor.red]
gradientx.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientx.endPoint = CGPoint(x: 1.0, y: 1.0)
gradientx.frame = button.bounds
button.layer.insertSublayer(gradientx, at: 0)
锚点是一个延伸,所以这是无关的梯度。对于Swift
extension UIViewController {
func makeGradientColor(`for` object : AnyObject , startPoint : CGPoint , endPoint : CGPoint) -> CAGradientLayer {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.colors = [(UIColor.red.cgColor), (UIColor.yellow.cgColor)]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = startPoint
gradient.endPoint = endPoint
gradient.frame = CGRect(x: 0.0, y: 0.0, width: object.bounds.size.width, height: object.bounds.size.height)
return gradient
}
}
如何使用?
if let layers = btn.layer.sublayers{
for layer in layers {
if layer.isKind(of: CAGradientLayer.self) {
layer.removeFromSuperlayer()
}
}
}
let start : CGPoint = CGPoint(x: 0.0, y: 0.0)
let end : CGPoint = CGPoint(x: 1.0, y: 1.0)
let gradient: CAGradientLayer = self.makeGradientColor(for: cell.bgView, startPoint: start, endPoint: end)
btn.layer.insertSublayer(gradient, at: 0)
试试看这对我有用
let button = UIButton(frame: CGRect(x: 60, y: 150, width: 200, height: 60))
button.setTitle("Email", for: .normal)
button.backgroundColor = .red
button.setTitleColor(UIColor.black, for: .normal)
button.addTarget(self, action: #selector(self.buttonTapped), for: .touchUpInside)
// Apply Gradient Color
let gradientLayer:CAGradientLayer = CAGradientLayer()
gradientLayer.frame.size = button.frame.size
gradientLayer.colors =
[UIColor.white.cgColor,UIColor.green.withAlphaComponent(1).cgColor]
//Use diffrent colors
button.layer.addSublayer(gradientLayer)
self.view.addSubview(button)
可以添加渐变颜色的起点和终点
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
有关更多详细说明,请参考这里已经有很多答案,我想添加我为实现这一点所做的工作。我使用这个自定义按钮GradientButton
import Foundation
import UIKit
class GradientButton: UIButton {
let gradientColors : [UIColor]
let startPoint : CGPoint
let endPoint : CGPoint
required init(gradientColors: [UIColor] = [UIColor.red, UIColor.blue],
startPoint: CGPoint = CGPoint(x: 0, y: 0.5),
endPoint: CGPoint = CGPoint(x: 1, y: 0.5)) {
self.gradientColors = gradientColors
self.startPoint = startPoint
self.endPoint = endPoint
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
let halfOfButtonHeight = layer.frame.height / 2
contentEdgeInsets = UIEdgeInsets(top: 10, left: halfOfButtonHeight, bottom: 10, right: halfOfButtonHeight)
layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
backgroundColor = UIColor.clear
// setup gradient
let gradient = CAGradientLayer()
gradient.frame = bounds
gradient.colors = gradientColors.map { $0.cgColor }
gradient.startPoint = startPoint
gradient.endPoint = endPoint
gradient.cornerRadius = 4
// replace gradient as needed
if let oldGradient = layer.sublayers?[0] as? CAGradientLayer {
layer.replaceSublayer(oldGradient, with: gradient)
} else {
layer.insertSublayer(gradient, below: nil)
}
// setup shadow
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: halfOfButtonHeight).cgPath
layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
layer.shadowOpacity = 0.85
layer.shadowRadius = 4.0
}
override var isHighlighted: Bool {
didSet {
let newOpacity : Float = isHighlighted ? 0.6 : 0.85
let newRadius : CGFloat = isHighlighted ? 6.0 : 4.0
let shadowOpacityAnimation = CABasicAnimation()
shadowOpacityAnimation.keyPath = "shadowOpacity"
shadowOpacityAnimation.fromValue = layer.shadowOpacity
shadowOpacityAnimation.toValue = newOpacity
shadowOpacityAnimation.duration = 0.1
let shadowRadiusAnimation = CABasicAnimation()
shadowRadiusAnimation.keyPath = "shadowRadius"
shadowRadiusAnimation.fromValue = layer.shadowRadius
shadowRadiusAnimation.toValue = newRadius
shadowRadiusAnimation.duration = 0.1
layer.add(shadowOpacityAnimation, forKey: "shadowOpacity")
layer.add(shadowRadiusAnimation, forKey: "shadowRadius")
layer.shadowOpacity = newOpacity
layer.shadowRadius = newRadius
let xScale : CGFloat = isHighlighted ? 1.025 : 1.0
let yScale : CGFloat = isHighlighted ? 1.05 : 1.0
UIView.animate(withDuration: 0.1) {
let transformation = CGAffineTransform(scaleX: xScale, y: yScale)
self.transform = transformation
}
}
}
}
您可以像这样创建GradientButton实例
let button = GradientButton.init(gradientColors:[UIColor.black, UIColor.white], startPoint: CGPoint(x: 0, y: 0), endPoint: CGPoint(x: 0, y: 1))
之后,直接将“ButtonCredit”类分配给故事板中的特定按钮。这里,我使用了一个UIView并在其中添加了按钮
@IBOutlet weak var btnCenter: UIButton!
@IBOutlet weak var viewCenter: UIView!
// Create a gradient layer
let gradient = CAGradientLayer()
// gradient colors in order which they will visually appear
gradient.colors = [UIColor.yello.cgColor, UIColor.blue.cgColor]
// Gradient from left to right
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
// set the gradient layer to the same size as the view
gradient.frame = viewCenter.bounds
// add the gradient layer to the views layer for rendering
viewCenter.layer.insertSublayer(gradient, at: 0)
// Tha magic! Set the button as the views mask
viewCenter.mask = btnCenter
//Set corner Radius and border Width of button
btnCenter.layer.cornerRadius = btnCenter.frame.size.height / 2
btnCenter.layer.borderWidth = 5.0
就这么简单:
import UIKit
class ActualGradientButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}
private lazy var gradientLayer: CAGradientLayer = {
let l = CAGradientLayer()
l.frame = self.bounds
l.colors = [UIColor.systemYellow.cgColor, UIColor.systemPink.cgColor]
l.startPoint = CGPoint(x: 0, y: 0.5)
l.endPoint = CGPoint(x: 1, y: 0.5)
l.cornerRadius = 16
layer.insertSublayer(l, at: 0)
return l
}()
}
如果您希望在按钮上添加渐变背景,而不是将渐变添加为子层并在
布局子视图中更改其帧
,我只需将按钮的背景指定为CAGradientLayer
,因此主层是渐变:
@IBDesignable
公共类GradientButton:UIButton{
公共重写类var layerClass:AnyClass{CAGradientLayer.self}
私有var gradientLayer:CAGradientLayer{layer as!CAGradientLayer}
@IBInspectable公共变量startColor:UIColor=.white{didSet{updateColors()}
@IBInspectable公共变量endColor:UIColor=.red{didSet{updateColors()}
//向IB公开起始点和终结点
@IBInspectable公共var起始点:CGPoint{
获取{gradientLayer.startPoint}
设置{gradientLayer.startPoint=newValue}
}
@IBInspectable公共变量终结点:CGPoint{
获取{gradientLayer.endPoint}
设置{gradientLayer.endPoint=newValue}
}
//在进行此操作时,让我们再公开一些图层属性,以便在IB中轻松调整它们
@i可检测的公共变量半径:CGFloat{
获取{layer.cornerRadius}
设置{layer.cornerRadius=newValue}
}
@IBInspectable public var borderWidth:CGFloat{
获取{layer.borderWidth}
设置{layer.borderWidth=newValue}
}
@i可检测的公共var边框颜色:UIColor{
获取{layer.borderColor.flatMap{UIColor(cgColor:$0)}
设置{layer.borderColor=newValue?.cgColor}
}
//初始化方法
公共重写init(帧:CGRect=.0){
super.init(frame:frame)
更新颜色()
}
必需初始化?(编码器:NSCoder){
super.init(编码器:编码器)
更新颜色()
}
}
专用扩展梯度按钮{
func updateColor(){
gradientLayer.colors=[startColor.cgColor,endColor.cgColor]
}
}
通过设置layerClass
,它只会使主层成为一个渐变层,该渐变层会自动调整到按钮的bounds
。这样做的一个优点是,如果对按钮大小的更改设置动画(例如旋转事件或其他事件),渐变也将正确设置动画
而且,这不是必需的,但是将此类设置为一个@IBDesignable
,这样就可以在IB中设置其属性,并且它将在脚本/NIB中正确呈现,而不需要在视图控制器中添加额外的代码。例如,我可以自定义IB中的角、边框和渐变颜色以及方向:
这很好,我尝试设置UIButton cornerRadius,但除非我删除渐变,否则它不会起任何作用,有没有办法解决这个问题?您是否尝试设置masksToBounds=Falset clipsToBounds=True不幸的是,这是完全错误的。这是iOS工程的一个绝对基础,当你添加一个层时,你必须在layoutSubviews
中对其进行塑造(实际上这就是layoutSubviews
存在的真正原因)。在添加新的gradientLayer之前,应更新答案以删除现有gradientLayer。在insertSublayer之前添加以下行。layer.name=“gradientLayer”self.layer.sublayers.filter{$0.name==layer.name}.first?.removeFromSuperLayer()我不同意最后一句话。虽然按钮是视图,但按钮背景与视图背景不同。按钮背景可以根据按钮状态而改变。当添加渐变层时,我们会失去这种效果。理想的解决方案是将渐变层捕捉到图像中,并将图像设置为按钮背景图像。另一个问题是,当按钮框架发生变化时,即从layoutSubviews
开始,层边界应该始终更新。作为记录,我确切地知道您在说什么,但它不适用于基于情节提要约束(不在代码运行时约束或框架中)的这篇文章。因为我已经发布了代码运行的视频证明,它满足了OP'
@IBOutlet weak var btnCenter: UIButton!
@IBOutlet weak var viewCenter: UIView!
// Create a gradient layer
let gradient = CAGradientLayer()
// gradient colors in order which they will visually appear
gradient.colors = [UIColor.yello.cgColor, UIColor.blue.cgColor]
// Gradient from left to right
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
// set the gradient layer to the same size as the view
gradient.frame = viewCenter.bounds
// add the gradient layer to the views layer for rendering
viewCenter.layer.insertSublayer(gradient, at: 0)
// Tha magic! Set the button as the views mask
viewCenter.mask = btnCenter
//Set corner Radius and border Width of button
btnCenter.layer.cornerRadius = btnCenter.frame.size.height / 2
btnCenter.layer.borderWidth = 5.0
import UIKit
class ActualGradientButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}
private lazy var gradientLayer: CAGradientLayer = {
let l = CAGradientLayer()
l.frame = self.bounds
l.colors = [UIColor.systemYellow.cgColor, UIColor.systemPink.cgColor]
l.startPoint = CGPoint(x: 0, y: 0.5)
l.endPoint = CGPoint(x: 1, y: 0.5)
l.cornerRadius = 16
layer.insertSublayer(l, at: 0)
return l
}()
}