2017-12-20 9 views
3

그라데이션이있는 뷰에 내부 테두리를 추가하고 싶습니다. 다음 코드는 작동하고 나에게이 결과CAGradientLayer에 마스크를 추가하면 UIBezierPath가 사라집니다.

enter image description here

import UIKit 

class InnerGradientBorderView: UIView { 
    override init(frame: CGRect) { 
     super.init(frame: frame) 
     backgroundColor = UIColor.clear 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     backgroundColor = UIColor.clear 
    } 

    override func draw(_ rect: CGRect) { 
     super.draw(rect) 

     addGradientInnerBorder(width: 8, color: FlatWhite()) 
    } 

    func addGradientInnerBorder(width: CGFloat, color: UIColor) { 

     // Setup 
     let topLeftO = CGPoint(x: 0, y: 0) 
     let topLeftI = CGPoint(x: width, y: width) 

     let topRightO = CGPoint(x: frame.width, y: 0) 
     let topRightI = CGPoint(x: frame.width - width, y: width) 

     let bottomLeftO = CGPoint(x: 0, y: frame.height) 
     let bottomLeftI = CGPoint(x: width, y: frame.height - width) 

     let bottomRightO = CGPoint(x: frame.width, y: frame.height) 
     let bottomRightI = CGPoint(x: frame.width - width, y: frame.height - width) 

     // Top 
     let topPoints = [topLeftO, topLeftI, topRightI, topRightO, topLeftO] 
     let topGradientPoints = [CGPoint(x: 0, y: 0), CGPoint(x: 0, y: 1)] 
     addGradientToBeizerPath(path: addClosedPathForPoints(points: topPoints), color: color, gradientPoints: topGradientPoints) 

     // Left 
     let leftPoints = [topLeftO, topLeftI, bottomLeftI, bottomLeftO, topLeftO] 
     let leftGradientPoints = [CGPoint(x: 0, y: 0), CGPoint(x: 1, y: 0)] 
     addGradientToBeizerPath(path: addClosedPathForPoints(points: leftPoints), color: color, gradientPoints: leftGradientPoints) 

     // Right 
     let rightPoints = [topRightO, topRightI, bottomRightI, bottomRightO, topRightO] 
     let rightGradientPoints = [CGPoint(x: 1, y: 0), CGPoint(x: 0, y: 0)] 
     addGradientToBeizerPath(path: addClosedPathForPoints(points: rightPoints), color: color, gradientPoints: rightGradientPoints) 

     // Bottom 
     let bottomPoints = [bottomLeftO, bottomLeftI, bottomRightI, bottomRightO, bottomLeftO] 
     let bottomGradientPoints = [CGPoint(x: 0, y: 1), CGPoint(x: 0, y: 0)] 
     addGradientToBeizerPath(path: addClosedPathForPoints(points: bottomPoints), color: color, gradientPoints: bottomGradientPoints) 
    } 

    func addClosedPathForPoints(points: [CGPoint]) -> UIBezierPath? { 
     guard points.count == 5 else { return nil } 

     let path = UIBezierPath() 
     path.move(to: points[0]) 
     path.addLine(to: points[1]) 
     path.addLine(to: points[2]) 
     path.addLine(to: points[3]) 
     path.addLine(to: points[4]) 

     path.close() 

     return path 
    } 

    func addGradientToBeizerPath(path: UIBezierPath?, color: UIColor, gradientPoints: [CGPoint]) { 
     guard let path = path, gradientPoints.count == 2 else { return } 

     let gradient = CAGradientLayer() 
     gradient.frame = path.bounds 
     gradient.colors = [color.cgColor, UIColor.clear.cgColor] 
     gradient.startPoint = gradientPoints[0] 
     gradient.endPoint = gradientPoints[1] 

//  let shapeMask = CAShapeLayer() 
//  shapeMask.path = path.cgPath 
//  gradient.mask = shapeMask 

     self.layer.insertSublayer(gradient, at: 0) 
    } 
} 

당신은 가장자리가 great.To가 나는 각도 가장자리를 제공하고, 그 문제를 해결하는 것이 보이지 않는 것을 볼 수 있습니다. 나는이 각도이 그라데이션에 마스크를 적용 할 때, 오른쪽 아래 경로는 다음과 같이 사라 :

enter image description here

좀 폐쇄 bezierPaths를 사용하여 그들에게 그라데이션을 적용 여기서 뭘하고 모든. 그래디언트에 마스크가있는 경우 (주석 처리 된 코드의 주석 처리가 제거됨) 경로 중 두 개가 사라집니다. 나는 뭔가를 이해하지 못한다고 생각합니다. 누군가 여기 CAShapeLayer를 올바르게 사용하는 방법을 알려주 길 바랍니다.

+1

가 이해가 안 :

가능한 간단한 수정은 점과 같은 좌표를 사용하도록 지정된 패스의 을 의 모양 레이어를 좌표계 변환하는 것입니다 'draw' 메소드 내부에서 뷰의'layer'에'CAGradientLayer'를 추가합니다. 이것은 저에게 잘못되었습니다. 당신이 달성하고자하는 것을 설명해 주시겠습니까? – Echelon

+0

이 크기를 조정할 수 있습니다. 그리고 뷰가 그려 지거나 다시 그려 질 필요가있을 때마다'draw' 메서드가 호출되기 때문에 나는 그곳에서 작업을 할 것이라고 생각했습니다. 더 나은 구현을 염두에 두셨습니까? –

+1

예, 'layoutSubviews' 또는 어딘가에 있습니다. 레이어 계층을 변경하는 것이 아니라 렌더링을 실제로 수행하려면'draw'를 오버라이드해야합니다. 'draw' 호출의 결과로 레이어를 삽입하고 내가 볼 수있는 레이어를 제거하지 않으므로 수백 가지 레이어로 끝나게됩니까? 나는 실제로 당신이 달성하려고 노력하는 것을 이해하기 위해 고심하고 있습니다 ... – Echelon

답변

1

This commentCALayer mask property에 은 완벽하게 설명합니다

마스크 층은이 하위 계층 인 것처럼 마스크 레이어의 좌표계에 살고있다. 귀하의 경우

는 오른쪽 및 아래쪽 구배 층의 원점이 클로징보기 (0, 0)에서 아니지만 (frame.width - width, 0) 및 각각의 (frame.height - width, 0). 한편, 에있는 점들의 좌표는 둘러싼 뷰의 (0, 0)에 대한 상대 좌표입니다. 당신이있는 이유

let gradient = CAGradientLayer() 
    gradient.frame = path.bounds 
    gradient.bounds = path.bounds // <<--- ADDED HERE! 
    gradient.colors = [color.cgColor, UIColor.clear.cgColor] 
    gradient.startPoint = gradientPoints[0] 
    gradient.endPoint = gradientPoints[1] 

    let shapeMask = CAShapeLayer() 
    shapeMask.path = path.cgPath 
    gradient.mask = shapeMask 

    self.layer.addSublayer(gradient) 
+0

이 문제가 해결되었습니다. 고맙습니다! –

관련 문제