Присвоение цвета от View к другому элементу

uiview

#1

У меня есть view у которого есть градиент и пара ПрозрачныХ labels. Мне нужно чтобы этот градиент остался под labels, а за границами лейблов цвет стал, как обычно, белым(прозрачным). Как это сделать? Для чего это нужно: если я буду присваивать каждому лейблу градиент он получится от края до края у каждого лейбла… а мне нужно чтобы было ощущение единой картины внутри лейблов.

Если есть другие варианты решения подобных задач - дайте знать)


#2
class CustomView: UIView {
    
    override static var layerClass: AnyClass {
        return CAGradientLayer.self
    }

    private var gradientLayer: CAGradientLayer {
        return layer as! CAGradientLayer
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        config()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        config()
    }
    
    private func config() {
        contentMode = .redraw
        backgroundColor = .clear
        gradientLayer.colors = [
            UIColor.blue.cgColor,
            UIColor.brown.cgColor,
            UIColor.black.cgColor
        ]
    }
    
    override func draw(_ rect: CGRect) {
        (layer.mask as? CAShapeLayer ?? { layer.mask = $0; return $0 }(CAShapeLayer())).path = subviews.reduce(UIBezierPath(), { path, view in path.append(UIBezierPath(rect: view.frame)); return path }).cgPath // 😊😊😊
    }
}


#3

Спасибо! Буду разбираться))


#4

Есть проблема. При попытке закруглить углы у label, цвет остается тот же. Это видно при создании рамки…


#5

Это не проблема а особенность реализации :slight_smile:
Что бы закруглять углы нужно отдельно для каждого лейбла расчитывать градиент:

class CustomLabel: UILabel {
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        config()
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        config()
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        setBackground()
    }
    private func config() {
        layer.masksToBounds = true
        layer.cornerRadius = 6
    }
    private func setBackground() {
        guard let superSize = superview?.frame.size else { return }
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        guard let context = CGContext(data: nil, width: Int(superSize.width), height: Int(superSize.height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) else { return }
        let colors = [
            UIColor.red.cgColor,
            UIColor.blue.cgColor,
            UIColor.green.cgColor
        ]
        guard let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: nil) else { return }
        context.drawLinearGradient(gradient, start: CGPoint(x: superSize.width / 2, y: superSize.height), end: CGPoint(x: superSize.width / 2, y: 0), options: .drawsBeforeStartLocation)
        guard let cgImage = context.makeImage()?.cropping(to: frame) else { return }
        backgroundColor = UIColor(patternImage: UIImage(cgImage: cgImage))
    }
}


#6

это получается для каждого лейбла создавать отдельный класс? или просто наследовать от суперкласса?


#7

Вместо UILabel используйте CustomLabel:

img

Или:

let label = CustomLabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))

#8

Спасибо вам огромное! Очень выручили. Если не трудно, подскажите ресурсы с CG/CA уроками. Как я посмотрел вы в них мастер🤘 А то я и половины из написанного вами кода не понимаю😅


#9

Даже не знаю что подсказать, я на практике такое изучал.