【问题标题】:Why gradient doesn't cover the whole width of the view为什么渐变不覆盖视图的整个宽度
【发布时间】:2017-06-24 14:09:05
【问题描述】:

我正在尝试将渐变应用于受限于主屏幕顶部、左侧和右侧的视图,但由于某种原因,渐变并未覆盖应用到的视图的整个宽度(请参阅图片中的黄色)。

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

我做错了什么?

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    问题很可能是您在viewDidLoad() 中添加了渐变层。直到viewDidLoad() 之后,视图才会设置为最终大小。

    您的视图控制器可能会在您的 XIB/Storyboard 中设置为与您运行它时不同的屏幕尺寸。 (假设您将其设置为 iPhone SE 尺寸,但您在 6 上运行它。6 的屏幕稍宽一些,因此当第一次加载视图时,图层将设置为 iPhone SE 的宽度。然后视图将被调整大小,但层的大小永远不会被调整。)

    您应该实现 UIViewController 方法viewDidLayoutSubviews(),并在该方法中调整图层的框架:

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

    这样,如果视图被调整大小(例如由于自动旋转),渐变层将相应地自动调整。

    编辑:

    正如 Sulthan 所指出的,默认情况下对图层框架的更改是动画的。您可能应该将帧更改包装在 CATransaction.begin/CATransaction.end 中并禁用操作,如下所示:

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

    【讨论】:

    • 顺便说一下,图层框架默认设置动画,因此最好将其包装到CATransaction 并调用setDisableActions(false)
    • @Duncan C - 我刚刚将我的代码移至viewDidLayoutSubviews() 并且它工作正常。
    • 如果我在视图(或表格视图单元格)中添加渐变怎么办?现在什么时候设置图层的框架?
    • 在 DrawRect 中。无论如何谢谢:)
    • 一般情况下,您应该尽可能避免使用drawRect()。它通常比使用图层并让它们自己绘制更慢且处理器密集度更高。我建议创建一个 UITableViewCell 的自定义子类,并在它的 frame 属性上给它一个 didSet 方法。在该方法中,更新单元格渐变层的框架。
    【解决方案2】:

    您无需设置起点和终点,因为您的目标是让渐变跨越整个视图。您已经使用 `

    进行了设置
    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)
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以将其转为UIView。所以它会自动调整大小,可以直接在 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
          }
      }
      

      【讨论】:

        【解决方案4】:

        一行代码就可以通过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)
        

        【讨论】:

          猜你喜欢
          • 2018-06-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-27
          • 1970-01-01
          • 2016-08-28
          • 1970-01-01
          • 2015-05-18
          相关资源
          最近更新 更多