如果不允许约束,如何移动 CAGradientLayer 及其父 UIView 容器?

How to move a CAGradientLayer with its parent UIView container if constraints are not allowed?

目前我有一个 UIView 容器位于 UITableView 上方。使用从 UIScrollView 的继承,我创建了一个 IBOutlet 容器视图的前导约束,并调整类似如下的约束:

func scrollViewDidScroll(_ scrollView: UIScrollView)
{
    if scrollView.contentOffset.y < 0
    {
        ...
        containerViewLeftConstraint.constant -= abs(scrollView.contentOffset.y) * 2
    }
    else
    {
       ...
       containerViewLeftConstraint.constant += abs(scrollView.contentOffset.y) * 2
    }
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
{
    resetContainerViewSize()
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
{
    resetContainerViewSize()
}

func resetContainerViewSize()
{
    containerViewLeftConstraint.constant = 0.0

    UIView.animate(withDuration: 0.4,
                   delay: 0.0,
                   usingSpringWithDamping: 0.7,
                   initialSpringVelocity: 0.5,
                   options: .curveEaseInOut,
                   animations: {
                    self.view.layoutIfNeeded()
                }, completion: nil)
}

为了演示,我将容器视图的 backgroundColor 设置为红色以直观地查看发生了什么:

我已经声明了一个 var gradientLayer = CAGradientLayer() 并将其作为子层添加到容器视图中,如下所示:

func createGradientOverlay()
{
    gradientLayer.frame = containerView.frame

    let colors = [UIColor.black.withAlphaComponent(0.5).cgColor,
                  UIColor.white.cgColor]

    gradientLayer.colors = colors
    gradientLayer.startPoint = CGPoint(x:0.0,
                               y:0.5)
    gradientLayer.endPoint = CGPoint(x:1.0, y:0.5);
    containerView.layer.addSublayer(gradientLayer)
}

然而,我得到的结果如下所示:

渐变层不粘附在容器视图的边界上,看起来像是浮动的。

我看过几个类似的问题:

  1. CALayers 没有在其 UIView 的边界变化时调整大小。为什么?
  2. Auto Layout constraint on CALayer IOS

所有人都建议像这样使用 viewDidLayoutSubviews

override func viewDidLayoutSubviews()
{
    super.viewDidLayoutSubviews()

    gradientLayer.frame = nameContainerView.frame
}

然而,渐变层仍然看起来是浮动的,并且没有遵守容器视图的约束。

我也尝试了以下方法但无济于事:

  1. gradientLayer.frame = nameContainerView.bounds
  2. gradientLayer.bounds = nameContainerView.bounds
  3. gradientLayer.frame = nameContainerView.layer.bounds
  4. gradientLayer.frame = nameContainerView.layer.frame

我该如何解决这个问题?

Pangu - 如果有人想要更多信息来帮助您,那么您应该提供这些信息,以便他们可以帮助您。现在回答你的问题。您可以通过两种方式干净地完成这两种方式,如果我能看到您的函数,可能是 3。

首先是创建一个使用 CAGradientLayer 作为背衬层的视图,然后您可以将自动布局应用于渐变视图。这是一个 class 你可以用我几分钟的时间。

import UIKit


class GradientBackedLayer: UIView {

    var colors : [UIColor] = [UIColor.black.withAlphaComponent(0.5),UIColor.white]{
        didSet{
            setUpGradient()
        }
    }

    var startPoint : CGPoint = CGPoint(x:0.0,y:0.5){
        didSet{
            setUpGradient()
        }
    }

    var endPoint : CGPoint = CGPoint(x:1.0, y:0.5){
        didSet{
            setUpGradient()
        }
    }

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

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

    func setUpGradient(){
        self.backgroundColor = .clear
        let cgColors = colors.map({[=10=].cgColor})
        if let gradientLayer = self.layer as? CAGradientLayer{
            gradientLayer.colors = cgColors
            gradientLayer.startPoint = startPoint
            gradientLayer.endPoint = endPoint
        }
    }

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

}

第二种是使用变换而不是更改容器上的约束,所有内容都将按比例缩放。如果这是你想要的方式,我会把这个留给你去解决。