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

Posted

技术标签:

【中文标题】如果不允许约束,如何移动 CAGradientLayer 及其父 UIView 容器?【英文标题】:How to move a CAGradientLayer with its parent UIView container if constraints are not allowed? 【发布时间】:2018-01-24 08:55:30 【问题描述】:

目前我有一个位于UITableView 上方的UIView 容器。使用从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)

但是,我得到的结果如图所示:

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

我看过几个类似的问题:

    CALayers didn't get resized on its UIView's bounds change. Why? Auto Layout constraint on CALayer ios How to get CAShapeLayer to work with constraints with swift? How to add a CAGradientLayer to a UIView when using programmatic constraints

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

override func viewDidLayoutSubviews()

    super.viewDidLayoutSubviews()

    gradientLayer.frame = nameContainerView.frame

但是,渐变层似乎仍然是浮动的,并且没有遵守容器视图的约束。

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

    gradientLayer.frame = nameContainerView.bounds gradientLayer.bounds = nameContainerView.bounds gradientLayer.frame = nameContainerView.layer.bounds gradientLayer.frame = nameContainerView.layer.frame

我该如何解决这个问题?

【问题讨论】:

显示 resetContainerViewSize 我会告诉你如何让它粘住 @agibson007 我认为从我发布的代码中可以清楚地看到 【参考方案1】:

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

首先是创建一个使用 CAGradientLayer 作为支持层的视图,然后您可以将自动布局应用到渐变视图。这是一个你可以用几分钟的课程。

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($0.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
    


第二种是使用变换而不是改变容器上的约束,一切都会按比例缩放。如果您愿意,我会留给您解决。

【讨论】:

以上是关于如果不允许约束,如何移动 CAGradientLayer 及其父 UIView 容器?的主要内容,如果未能解决你的问题,请参考以下文章

自动布局的 Xcode 故事板问题不允许我移动对象 origin.y 值

如果允许JVM在垃圾收集期间移动堆内存,那么垃圾收集如何不因移动指针而导致JNI爆炸?

检查约束不允许我添加数据

oracle 如何创建,可空唯一约束

如何使用自动布局约束为移动 UILabel 设置动画?

完整约束二