Разное отображение CAShapeLayer в ячейках


#1

У меня есть коллекция с двумя ячейками в одной рисуется нормально, а во второй по-другому, хотя код один и тот же

let card : CAShapeLayer = {
let card = CAShapeLayer()
return card
}()

let cardPath = UIBezierPath()

    cardPath.move(to: CGPoint(x: 30, y: bounds.height * 0.214))
    cardPath.addLine(to: CGPoint(x: center.x - bounds.width * 0.11, y: bounds.height * 0.214))
    cardPath.addArc(withCenter: CGPoint(x: center.x - bounds.width * 0.11, y: bounds.height * 0.214 - 20), radius: 20, startAngle: .pi / 2, endAngle: .pi / 4, clockwise: false)
    cardPath.addLine(to: CGPoint(x: center.x - 8, y: bounds.height * 0.177 - 6 ))
    cardPath.addArc(withCenter: CGPoint(x: center.x, y: bounds.height * 0.177), radius: 10, startAngle: .pi * -3/4, endAngle: .pi / -4, clockwise: true)
    cardPath.addLine(to: CGPoint(x: center.x + bounds.width * 0.11 - 14, y: bounds.height * 0.214 - 6))
    cardPath.addArc(withCenter: CGPoint(x: center.x + bounds.width * 0.11, y: bounds.height * 0.214 - 20), radius: 20, startAngle: .pi * 3/4, endAngle: .pi / 2, clockwise: false)
    cardPath.addLine(to: CGPoint(x: bounds.width - 30, y: bounds.height * 0.214))
    cardPath.addQuadCurve(to: CGPoint(x: bounds.width - 20, y: bounds.height * 0.214 + 10), controlPoint: CGPoint(x: bounds.width - 20, y: bounds.height * 0.214))
    cardPath.addLine(to: CGPoint(x: bounds.width - 20, y: bounds.height - 30))
    cardPath.addQuadCurve(to: CGPoint(x: bounds.width - 30, y: bounds.height - 20), controlPoint: CGPoint(x: bounds.width - 20, y: bounds.height - 20))
    cardPath.addLine(to: CGPoint(x: 30, y: bounds.height - 20))
    cardPath.addQuadCurve(to: CGPoint(x: 20, y: bounds.height - 30), controlPoint: CGPoint(x: 20, y: bounds.height - 20))
    cardPath.addLine(to: CGPoint(x: 20, y: bounds.height * 0.214 + 10))
    cardPath.addQuadCurve(to: CGPoint(x: 30, y: bounds.height * 0.214), controlPoint: CGPoint(x: 20, y: bounds.height * 0.214))
    
    card.fillColor = UIColor.clear.cgColor
    card.strokeColor = UIColor.black.cgColor
    card.lineWidth = 1
    card.strokeEnd = 1
    card.path = cardPath.cgPath
    
    layer.addSublayer(card)

Думаю, тут суть не в коде, а в том , что размеры ячеек где-то как-то отличаются, если кто сталкивался - подскажите


#2

Попробуйте

override func prepareForReuse() {
    super.prepareForReuse()
    card.removeFromSuperLayer()
}

#3

Не помогло, всё также


#4

Можете показать класс ячейки целиком?


#5

class CalculatorCell: UICollectionViewCell {

let gradientMask: CAShapeLayer = {
    let mask = CAShapeLayer()
    mask.fillColor = UIColor.white.cgColor
    return mask
}()

let gradientLayer : CAGradientLayer = {
    let gradient = CAGradientLayer()
    
    gradient.colors = [UIColor(red: 0.341, green: 0.494, blue: 1, alpha: 1).cgColor, UIColor(red: 1, green: 0.318, blue: 1, alpha: 1).cgColor]
    gradient.locations = [0.0, 1.0]
    gradient.startPoint = CGPoint(x: 1, y: 0)
    gradient.endPoint = CGPoint(x: 0, y: 1)
    
    return gradient
}()

let circleAtGradient : CAShapeLayer = {
    let circle = CAShapeLayer()
    circle.fillColor = UIColor.white.withAlphaComponent(0.25).cgColor
    return circle
}()
/*
let qurve: CAShapeLayer = {
    let qurve = CAShapeLayer()  // ещё какая-нибудь кривая на градиенте
    return qurve
}()
*/

let card : CAShapeLayer = {
    let card = CAShapeLayer()
    return card
}()

override init(frame: CGRect) {
    super.init(frame: frame)
    
    backgroundColor = .white
    print("INIT height \(bounds.height)")
    print("INIT width\(bounds.width)")
    
    // Gradient Mask
    gradientMask.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height * 1/3.5), byRoundingCorners: UIRectCorner(arrayLiteral: [.topLeft, .topRight]), cornerRadii: CGSize(width: 20, height: 20)).cgPath
    layer.addSublayer(gradientMask)
    
    // Gradient
    gradientLayer.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height * 1/3.5)
    gradientLayer.mask = gradientMask
    layer.addSublayer(gradientLayer)
    
    // Circle on gradient
    let path = UIBezierPath()
    path.addArc(withCenter: CGPoint(x: bounds.width - bounds.height * 1/5 * 0.7, y: 0), radius: bounds.height * 1/5, startAngle: .pi, endAngle: .pi / 4, clockwise: false)
    path.addLine(to: CGPoint(x: bounds.width, y: 20))
    path.addQuadCurve(to: CGPoint(x: bounds.width - 20, y: 0), controlPoint: CGPoint(x: bounds.width, y: 0))
    path.addLine(to: CGPoint(x: bounds.width - bounds.height * 1/5, y: 0))
    circleAtGradient.path = path.cgPath
    layer.addSublayer(circleAtGradient)
    
    // CARD
    let cardPath = UIBezierPath()
    
    cardPath.move(to: CGPoint(x: 30, y: bounds.height * 0.214))
    cardPath.addLine(to: CGPoint(x: center.x - bounds.width * 0.11, y: bounds.height * 0.214))
    cardPath.addArc(withCenter: CGPoint(x: center.x - bounds.width * 0.11, y: bounds.height * 0.214 - 20), radius: 20, startAngle: .pi / 2, endAngle: .pi / 4, clockwise: false)
    cardPath.addLine(to: CGPoint(x: center.x - 8, y: bounds.height * 0.177 - 6 ))
    cardPath.addArc(withCenter: CGPoint(x: center.x, y: bounds.height * 0.177), radius: 10, startAngle: .pi * -3/4, endAngle: .pi / -4, clockwise: true)
    cardPath.addLine(to: CGPoint(x: center.x + bounds.width * 0.11 - 14, y: bounds.height * 0.214 - 6))
    cardPath.addArc(withCenter: CGPoint(x: center.x + bounds.width * 0.11, y: bounds.height * 0.214 - 20), radius: 20, startAngle: .pi * 3/4, endAngle: .pi / 2, clockwise: false)
    cardPath.addLine(to: CGPoint(x: bounds.width - 30, y: bounds.height * 0.214))
    cardPath.addQuadCurve(to: CGPoint(x: bounds.width - 20, y: bounds.height * 0.214 + 10), controlPoint: CGPoint(x: bounds.width - 20, y: bounds.height * 0.214))
    cardPath.addLine(to: CGPoint(x: bounds.width - 20, y: bounds.height - 30))
    cardPath.addQuadCurve(to: CGPoint(x: bounds.width - 30, y: bounds.height - 20), controlPoint: CGPoint(x: bounds.width - 20, y: bounds.height - 20))
    cardPath.addLine(to: CGPoint(x: 30, y: bounds.height - 20))
    cardPath.addQuadCurve(to: CGPoint(x: 20, y: bounds.height - 30), controlPoint: CGPoint(x: 20, y: bounds.height - 20))
    cardPath.addLine(to: CGPoint(x: 20, y: bounds.height * 0.214 + 10))
    cardPath.addQuadCurve(to: CGPoint(x: 30, y: bounds.height * 0.214), controlPoint: CGPoint(x: 20, y: bounds.height * 0.214))
    cardPath.close()
    
    card.fillColor = UIColor.clear.cgColor
    card.strokeColor = UIColor.black.cgColor
    card.lineWidth = 1
    card.strokeEnd = 1
    card.path = cardPath.cgPath
    
    layer.addSublayer(card)
    
    
    
}

required init?(coder aDecoder: NSCoder) {
    fatalError("Error")
}

override func prepareForReuse() {
    super.prepareForReuse()
    card.removeFromSuperlayer()
}

override func layoutSubviews() {
    super.layoutSubviews()
    
    //clipsToBounds = false
    //layer.masksToBounds = true
    layer.cornerRadius = 25
    layer.shadowRadius = 5
    layer.shadowOpacity = 0.5
    layer.shadowOffset = CGSize(width: 0, height: 0)
    
    print("layout height \(bounds.height)" )
    print("layout width\(bounds.width)")
}

}


#6

Остальные Layer-ы нормально отрисовываются, и если что-то не так у меня в классе. можете посоветовать как это исправить, так как я новичок, там я уверен не всё идеально)


#7

Попробуйте тогда вставить card.removeFromSuperlayer() перед layer.addSublayer(card)


#8

тоже не получается :frowning:


#9

Я в общем то починил, но получилось не очень круто, поэтому если что на ум придёт - буду очень рад услышать :slight_smile:


#10

Буду рад увидеть. Может я что-то упустил.


#11

let screenWidth = UIScreen.main.bounds.maxX - 60
cardPath.move(to: CGPoint(x: 30, y: bounds.height * 0.214))
cardPath.addLine(to: CGPoint(x: screenWidth / 2 - bounds.width * 0.11, y: bounds.height * 0.214))
cardPath.addArc(withCenter: CGPoint(x: screenWidth / 2 - bounds.width * 0.11, y: bounds.height * 0.214 - 20), radius: 20, startAngle: .pi / 2, endAngle: .pi / 4, clockwise: false)
cardPath.addLine(to: CGPoint(x: screenWidth / 2 - 8, y: bounds.height * 0.177 - 6 ))
cardPath.addArc(withCenter: CGPoint(x: screenWidth / 2, y: bounds.height * 0.177), radius: 10, startAngle: .pi * -3/4, endAngle: .pi / -4, clockwise: true)
cardPath.addLine(to: CGPoint(x: screenWidth / 2 + bounds.width * 0.11 - 14, y: bounds.height * 0.214 - 6))
cardPath.addArc(withCenter: CGPoint(x: screenWidth / 2 + bounds.width * 0.11, y: bounds.height * 0.214 - 20), radius: 20, startAngle: .pi * 3/4, endAngle: .pi / 2, clockwise: false)
cardPath.addLine(to: CGPoint(x: bounds.width - 30, y: bounds.height * 0.214))
cardPath.addQuadCurve(to: CGPoint(x: bounds.width - 20, y: bounds.height * 0.214 + 10), controlPoint: CGPoint(x: bounds.width - 20, y: bounds.height * 0.214))
cardPath.addLine(to: CGPoint(x: bounds.width - 20, y: bounds.height - 30))
cardPath.addQuadCurve(to: CGPoint(x: bounds.width - 30, y: bounds.height - 20), controlPoint: CGPoint(x: bounds.width - 20, y: bounds.height - 20))
cardPath.addLine(to: CGPoint(x: 30, y: bounds.height - 20))
cardPath.addQuadCurve(to: CGPoint(x: 20, y: bounds.height - 30), controlPoint: CGPoint(x: 20, y: bounds.height - 20))
cardPath.addLine(to: CGPoint(x: 20, y: bounds.height * 0.214 + 10))
cardPath.addQuadCurve(to: CGPoint(x: 30, y: bounds.height * 0.214), controlPoint: CGPoint(x: 20, y: bounds.height * 0.214))
cardPath.close()

В общем все center.x заменил на UIScreen.main.bounds.maxX /2


#12

А если так

let screenWidth = frame.width


#13

Да, работает, спасибо большое за потраченное время, может объясните, почему раньше не работало, а то я не понимаю


#14

Если честно, я пока сам не до конца понял.
Получается center.x берется не от фрейма ячейки, а от чего-то выше.
Еще не приходилось делать такие отрисовки в ячейках.


#15

Хорошо, буду знать, еще раз спасибо