代码之家  ›  专栏  ›  技术社区  ›  Deepak Sharma

UITextView渐变层应用不起作用

  •  0
  • Deepak Sharma  · 技术社区  · 4 年前

    我想在UITextView的顶部10%和底部10%上应用渐变层。为此,我放置了一个名为container view的虚拟UIView,并将UITextView作为它的子视图。然后我添加了以下代码:

       if let containerView = textView.superview {
            let gradient = CAGradientLayer(layer: containerView.layer)
            gradient.frame = containerView.bounds
            gradient.colors = [UIColor.clear.cgColor, UIColor.black.cgColor]
            gradient.locations = [0.0, 0.1, 0.9, 1.0]
            containerView.layer.mask = gradient
        } 
    

    但是梯度只适用于顶部,而不是底部。代码有问题吗?

    此外,如果通过修改容器视图的约束随时调整其大小,是否每次都需要编辑遮罩层?

    编辑:这里是@DonMag answer的输出。

    enter image description here

    但我想要的是,在这张图片中,文本在底部淡出。

    enter image description here

    编辑2:

    下面是DonMag修改答案后的截图。

    enter image description here enter image description here

    0 回复  |  直到 4 年前
        1
  •  2
  •   Mojtaba Hosseini    4 年前

    @DongMag的解决方案非常复杂。相反,您只需要实现一个掩码,如下所示:

    @IBDesignable
    class MaskableLabel: UILabel {
        var maskImageView = UIImageView()
    
        @IBInspectable
        var maskImage: UIImage? {
            didSet {
                maskImageView.image = maskImage
                updateView()
            }
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
            updateView()
        }
    
        func updateView() {
            if maskImageView.image != nil {
                maskImageView.frame = bounds
                mask = maskImageView
            }
        }
    }
    

    然后用一个简单的渐变遮罩 like this ,你甚至可以在故事板上看到它。

    Preview

    笔记 :您可以使用此方法并替换 UILabel 与任何其他你想子类化的视图。

    这是 the example project on the GitHub

        2
  •  1
  •   DonMag    4 年前

    编辑 -在澄清预期效果后。。。

    我最初的回答是,为什么你只看到顶部看台上的坡度:

    你只能看到顶部的梯度,因为你给了它 地点,但仅限于 颜色。

    所以,现在你提供了一张你想做的事情的图片。。。

    用这个 DoubleGradientMaskView 作为文本视图的“容器”视图:

    class DoubleGradientMaskView: UIView {
        
        let gradientLayer = CAGradientLayer()
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
        func commonInit() -> Void {
            gradientLayer.colors = [UIColor.clear.cgColor, UIColor.black.cgColor, UIColor.black.cgColor, UIColor.clear.cgColor]
            gradientLayer.locations = [0.0, 0.1, 0.9, 1.0]
            layer.mask = gradientLayer
        }
        
        override func layoutSubviews() {
            super.layoutSubviews()
            gradientLayer.frame = bounds
        }
        
    }
    

    控制器示例:

    class GradientTextViewViewController: UIViewController {
        
        let textView = UITextView()
        let containerView = DoubleGradientMaskView()
        let bkgImageView = UIImageView()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            [bkgImageView, textView, containerView].forEach {
                $0.translatesAutoresizingMaskIntoConstraints = false
            }
            
            bkgImageView.contentMode = .scaleAspectFill
            if let img = UIImage(named: "background") {
                bkgImageView.image = img
            } else {
                bkgImageView.backgroundColor = .blue
            }
            
            view.addSubview(bkgImageView)
            view.addSubview(containerView)
            containerView.addSubview(textView)
            
            // respect safe area
            let g = view.safeAreaLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // add an image view so we can see the white text
                bkgImageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
                bkgImageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
                bkgImageView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
                bkgImageView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
    
                // constraint text view inside container
                textView.topAnchor.constraint(equalTo: containerView.topAnchor),
                textView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
                textView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
                textView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
                
                // constrain container Top / Bottom 40, Leading / Trailing 40
                containerView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
                containerView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
                containerView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
                containerView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -40.0),
    
            ])
            
            textView.isScrollEnabled = true
            
            textView.font = UIFont.systemFont(ofSize: 48.0, weight: .bold)
            textView.textColor = .white
            textView.backgroundColor = .clear
    
            textView.text = String((1...20).flatMap { "This is row \($0)\n" })
            
        }
    
    }
    

    结果:

    enter image description here

    或者,用蓝色背景代替图像:

    enter image description here


    你只能看到顶部的梯度,因为你给了它 地点,但仅限于 颜色。

    将颜色更改为:

    gradient.colors = [UIColor.clear.cgColor, UIColor.black.cgColor, UIColor.black.cgColor, UIColor.clear.cgColor]
    

    可能会给你想要的样子。。。但你需要额外的代码来处理尺寸变化。

    如果将此类用作“容器”视图,大小调整将自动进行:

    class DoubleGradientView: UIView {
        
        var gradientLayer: CAGradientLayer!
        
        override class var layerClass: AnyClass {
            return CAGradientLayer.self
        }
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
        func commonInit() -> Void {
            gradientLayer = self.layer as? CAGradientLayer
            gradientLayer.colors = [UIColor.black.cgColor, UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.black.cgColor]
            gradientLayer.locations = [0.0, 0.1, 0.9, 1.0]
        }
        
    }
    

    下面是一个示例控制器。它创建了两个“容器中的文本视图”

    • 最上面的一个可以滚动,高度为100。
    • 底部的一个不可滚动,因此在您键入时,它会根据文本调整其高度。

    两者都是以60分的速度进行前导/尾随约束的,因此在旋转设备时,您还会看到自动渐变更新。

    class GradientBehindTextViewViewController: UIViewController {
        
        let textView1 = UITextView()
        let containerView1 = DoubleGradientView()
    
        let textView2 = UITextView()
        let containerView2 = DoubleGradientView()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            [textView1, containerView1, textView2, containerView2].forEach {
                $0.translatesAutoresizingMaskIntoConstraints = false
            }
            
            containerView1.addSubview(textView1)
            view.addSubview(containerView1)
            
            containerView2.addSubview(textView2)
            view.addSubview(containerView2)
            
            // respect safe area
            let g = view.safeAreaLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // constraint text view inside container
                textView1.topAnchor.constraint(equalTo: containerView1.topAnchor),
                textView1.leadingAnchor.constraint(equalTo: containerView1.leadingAnchor),
                textView1.trailingAnchor.constraint(equalTo: containerView1.trailingAnchor),
                textView1.bottomAnchor.constraint(equalTo: containerView1.bottomAnchor),
    
                // constrain container Top + 40, Leading / Trailing 80
                containerView1.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
                containerView1.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 80.0),
                containerView1.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -80.0),
    
                // text view 1 will have scrolling enabled, so we'll set its height to 100
                containerView1.heightAnchor.constraint(equalToConstant: 100.0),
                
                // constraint text view inside container
                textView2.topAnchor.constraint(equalTo: containerView2.topAnchor),
                textView2.leadingAnchor.constraint(equalTo: containerView2.leadingAnchor),
                textView2.trailingAnchor.constraint(equalTo: containerView2.trailingAnchor),
                textView2.bottomAnchor.constraint(equalTo: containerView2.bottomAnchor),
                
                // constrain container2 Top to container1 bottom + 40, Leading / Trailing 80
                containerView2.topAnchor.constraint(equalTo: containerView1.bottomAnchor, constant: 40.0),
                containerView2.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 80.0),
                containerView2.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -80.0),
                
                // text view 2 will NOT scroll (it will size with the text) so no height / bottom
    
            ])
            
            // text view 1 should scroll
            textView1.isScrollEnabled = true
            
            // text view 1 should NOT scroll we want the text view to size itelf as we type
            textView2.isScrollEnabled = false
            
            // let the gradient show through
            textView1.backgroundColor = .clear
            textView2.backgroundColor = .clear
    
            textView1.text = "Initial text for text view 1."
            textView2.text = "Initial text for text view 2."
    
        }
        
    }