简体   繁体   English

为什么渐变不覆盖视图的整个宽度

[英]Why gradient doesn't cover the whole width of the view

I'm trying to apply a gradient to a view which is constraint to the top, left and right of the main screen but for some reason the gradient doesn't cover the whole width of the view that is applied to (see the yellow in the picture).我正在尝试将渐变应用于主屏幕顶部、左侧和右侧的约束视图,但由于某种原因,渐变未覆盖所应用视图的整个宽度(请参见中的黄色图片)。

class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let gradient = CAGradientLayer()
        gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
        gradient.startPoint = CGPoint(x:00, y:00)
        gradient.endPoint = CGPoint(x:0, y:0.6)
        gradient.frame = myView.bounds
        myView.clipsToBounds = true
        myView.layer.insertSublayer(gradient, at: 0)
    }
}

What am I doing wrong?我究竟做错了什么?

在此处输入图像描述

The problem is likely that you are adding the gradient layer in viewDidLoad() .问题很可能是您在viewDidLoad()中添加了渐变层。 A view doesn't get set to it's final size until after viewDidLoad() .直到viewDidLoad()之后,视图才会设置为其最终大小。

Your view controller may be set up in your XIB/Storyboard for a different screen-size than you're running it on.您的视图控制器可能在您的 XIB/Storyboard 中设置为与您运行时不同的屏幕尺寸。 (Say you have it set to iPhone SE size, but you're running it on a 6. The 6's screen is a little wider, so the layer will get set to the width of the iPhone SE, when the view is first loaded. Then the view will be resized, but the layer's size will never be adjusted.) (假设您已将其设置为 iPhone SE 大小,但您在 6 上运行它。6 的屏幕更宽一些,因此在首次加载视图时,图层将设置为 iPhone SE 的宽度。然后将调整视图大小,但永远不会调整图层的大小。)

You should implement the UIViewController method viewDidLayoutSubviews() , and in that method, adjust the layer's frame:您应该实现 UIViewController 方法viewDidLayoutSubviews() ,并在该方法中调整图层的框架:

override func viewDidLayoutSubviews() {
  gradientLayer.frame = self.view.bounds
}

That way if the view gets resized (due to auto-rotation, for example) the gradient layer will be automatically adjusted accordingly.这样,如果视图被调整大小(例如由于自动旋转),渐变层将相应地自动调整。

EDIT:编辑:

As pointed out by Sulthan, changes to a layer's frame are animated by default.正如 Sulthan 所指出的,默认情况下对图层帧的更改是动画的。 You should probably wrap the frame change in a CATransaction.begin / CATransaction.end and disable actions, like below:您可能应该将帧更改包装在CATransaction.begin / CATransaction.end并禁用操作,如下所示:

override func viewDidLayoutSubviews() {
  CATransaction.begin()
  CATransaction.setDisableActions(true)
  gradientLayer.frame = self.view.bounds
  CATransaction.commit()
}

You needn't set the start and end point, given your goal is to have the gradient span the entire view.您无需设置起点和终点,因为您的目标是让渐变跨越整个视图。 You're already setting that with `你已经用`设置了

gradientLayer.frame = self.view.bounds

` `

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    var gradientLayer: CAGradientLayer!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        createGradientLayer()
    }

    func createGradientLayer() {
        gradientLayer = CAGradientLayer()

        gradientLayer.frame = self.view.bounds

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

        self.view.layer.addSublayer(gradientLayer)
    }
}

You can turn it to a UIView .你可以把它变成一个UIView So it will resize automatically and can be seen directly in the Storyboard:所以它会自动调整大小,可以直接在 Storyboard 中看到:

@IBDesignable
final class GradientView: UIView {

    @IBInspectable var firstColor: UIColor = .clear { didSet { updateView() } }
    @IBInspectable var secondColor: UIColor = .clear { didSet { updateView() } }

    @IBInspectable var startPoint: CGPoint = CGPoint(x: 0, y: 0) { didSet { updateView() } }
    @IBInspectable var endPoint: CGPoint = CGPoint(x: 1, y: 1) { didSet { updateView() } }

    override class var layerClass: AnyClass { get { CAGradientLayer.self } }

    override func layoutSubviews() {
        super.layoutSubviews()
        updateView()
        layer.frame = bounds
    }

    private func updateView() {
        let layer = self.layer as! CAGradientLayer
        layer.colors = [firstColor, secondColor].map {$0.cgColor}
        layer.startPoint = startPoint
        layer.endPoint = endPoint
    }
}

预览

simply put you gredient layer in main thred like this像这样简单地把你的成分层放在主要线程中

 DispatchQueue.main.async {
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = self.viewGredient.bounds
        gradientLayer.colors = [UIColor.black.cgColor, UIColor.white.cgColor]
        gradientLayer.locations = [0.0, 1.0]
        self.viewGredient.layer.addSublayer(gradientLayer)
    }

You can simplify it by CustomClass with one line of code你可以用一行代码通过 CustomClass 来简化它

class GradientView: UIView {
   override class var layerClass: Swift.AnyClass {
      return CAGradientLayer.self
   }
}


// MARK: Usage

@IBOutlet weak var myView: GradientView!

guard let gradientLayer = myView.layer as? CAGradientLayer else { return }
gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x:0, y:0.6)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM