ड्रा (_ rect :) फ़ंक्शन का उपयोग करते समय अजीब काले कोनों

Dec 07 2020

अगर मैं अपने फंक्शन के UIBezierPathअंदर कोड डालता हूं तो मुझे draw(_ rect:)देखने और पूंछ के आसपास ये अजीब बहुत पतले काले कोने मिलते हैं। दृश्य को खींचते समय (उदाहरण प्रस्तुत दृश्य नियंत्रक के भीतर) ये पतली रेखाएँ भी टिमटिमाना शुरू कर देती हैं। मुझे लगता है कि यह एक अजीब प्रतिपादन बग है। क्या किसी को पता है कि क्या इसे ठीक करने का कोई तरीका है?

class RenderingView: UIView {
    lazy var backgroundView: UIView = {
        let view = UIView()
        view.layer.cornerRadius = 8
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    private lazy var shadowView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    private lazy var textLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Rendering Bug"
        return label
    }()

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

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setup() {
        backgroundColor = .clear
        backgroundView.backgroundColor = .yellow
        layer.borderWidth = 0
        setupLayout()
    }

    private func setupLayout() {
        [shadowView, backgroundView, textLabel].forEach(addSubview)

        backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        backgroundView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

        shadowView.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor).isActive = true
        shadowView.topAnchor.constraint(equalTo: backgroundView.topAnchor).isActive = true
        shadowView.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor).isActive = true
        shadowView.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor).isActive = true

        textLabel.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 10).isActive = true
        textLabel.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: -10).isActive = true
        textLabel.topAnchor.constraint(equalTo: backgroundView.topAnchor, constant: 10).isActive = true
        textLabel.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor, constant: -10).isActive = true
    }

    override func draw(_ rect: CGRect) {
        shapeBackground()
    }

    private func shapeBackground() {
        let tailLayer = CAShapeLayer()

        let bezierPath = UIBezierPath(roundedRect: CGRect(x: backgroundView.bounds.minX,
                                                          y: backgroundView.bounds.minY,
                                                          width: backgroundView.bounds.width,
                                                          height: backgroundView.bounds.height - 12),
                                      cornerRadius: 8)

        let shadowBezierPath = UIBezierPath(roundedRect: CGRect(x: backgroundView.bounds.minX + 5,
                                                                y: backgroundView.bounds.minY + 10,
                                                                width: backgroundView.bounds.width - 10,
                                                                height: backgroundView.bounds.height - 12 - 10),
                                            cornerRadius: 8)

        [bezierPath, shadowBezierPath].forEach {
            $0.move(to: CGPoint(x: backgroundView.bounds.midX - 12, y: backgroundView.bounds.maxY - 12)) $0.addLine(to: CGPoint(x: backgroundView.bounds.midX, y: backgroundView.bounds.maxY))
            $0.addLine(to: CGPoint(x: backgroundView.bounds.midX + 12, y: backgroundView.bounds.maxY - 12)) $0.fill()
            $0.close()
        }

        tailLayer.path = bezierPath.cgPath
        tailLayer.fillColor = UIColor.white.cgColor

        shadowView.layer.shadowPath = shadowBezierPath.cgPath
        shadowView.layer.cornerRadius = 8

        backgroundView.layer.masksToBounds = true
        backgroundView.layer.mask = tailLayer
    }
}

संपादित करें:addClip() इन कोनों से छुटकारा पाने के लिए मुझे बीज़ियर रास्तों पर उपयोग करना पड़ा

जवाब

2 Eskils Dec 07 2020 at 23:44

सुनिश्चित नहीं है कि यह वही है जो आप के लिए लक्ष्य कर रहे हैं, लेकिन यह निर्दोष दिखता है जब आप shapeBackground()विधि से बाहर जाते हैं draw(_ rect:)और कुछ मामूली संशोधन करते हैं।

मैंने आपके कुछ ड्रॉइंग रूटीन को अंदर से संशोधित किया है shapeBackground(), और फंक्शन को स्थानांतरित layoutSubviews()करने के लिए बाधाओं से बने फ्रेम से पूंछ की स्थिति की गणना की है। मैं भी के लिए कुछ चर जोड़ा tailWidth, और tailHeight

इस तरह:

class RenderingView: UIView {
    lazy var backgroundView: UIView = {
        let view = UIView()
        view.layer.cornerRadius = 8
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    private lazy var shadowView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    private lazy var textLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "No Rendering Bug"
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setup() {
        backgroundColor = .clear
        backgroundView.backgroundColor = .systemTeal
        //backgroundView.frame.size = CGSize(width: 100, height: 100)
        layer.borderWidth = 0
        setupLayout()
    }
    
    private func setupLayout() {
        [shadowView, backgroundView, textLabel].forEach(addSubview)
        
        backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        backgroundView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        
        shadowView.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor).isActive = true
        shadowView.topAnchor.constraint(equalTo: backgroundView.topAnchor).isActive = true
        shadowView.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor).isActive = true
        shadowView.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor).isActive = true
        
        textLabel.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 10).isActive = true
        textLabel.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: -10).isActive = true
        textLabel.topAnchor.constraint(equalTo: backgroundView.topAnchor, constant: 10).isActive = true
        textLabel.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor, constant: -10).isActive = true
        
        
    }
    
    override func didMoveToWindow() {
        super.didMoveToWindow()
        
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        shapeBackground(color: UIColor.systemTeal)
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
    }
    
    private func shapeBackground(color: UIColor) {
        let tailLayer = CAShapeLayer()
        tailLayer.name = "tailLayer"
        
        let tailWidth: CGFloat = 16
        let tailHeight: CGFloat = 10
        
        let bezierPath = UIBezierPath()
        let shadowBezierPath = UIBezierPath()
        
        [bezierPath, shadowBezierPath].forEach {
            $0.move(to: CGPoint(x: 0, y: 0)) $0.addLine(to: CGPoint(x: tailWidth / 2, y: tailHeight))
            $0.addLine(to: CGPoint(x: tailWidth, y: 0)) $0.fill()
            $0.close()
        }
        
        tailLayer.path = bezierPath.cgPath
        tailLayer.fillColor = color.cgColor
        
        shadowView.layer.shadowPath = shadowBezierPath.cgPath
        shadowView.layer.cornerRadius = 8
        
        print(backgroundView.bounds.width)
        
        tailLayer.frame = CGRect(x: (backgroundView.bounds.width - tailWidth) / 2,
                                 y: backgroundView.bounds.maxY,
                                 width: tailWidth,
                                 height: tailHeight)
        
        backgroundView.layer.masksToBounds = false
        backgroundView.layer.addSublayer(tailLayer)
    }
}