2017-12-20 23 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を使用して、それらにグラデーションを適用しています。グラデーションにマスクがある場合(コメント付きコードのコメントが外されている)、パスの2つが消えます。私は何かを理解していないと感じているので、ここの誰かがCAShapeLayerの使い方を正しく教えてくれればうれしいです。

+1

あなたがいる理由私は理解していません'draw'メソッドの内側から' CAGradientLayer'をビューの 'layer'に追加すると、間違って感じられます。あなたが達成しようとしていることを説明できますか? – Echelon

+0

これを追加するのはサイズ変更可能です。ビューを描画するか再描画する必要があるときはいつでも、 'draw'メソッドが呼び出されるので、私はそこで作業をすると考えました。あなたはより良い実装を念頭に置いていましたか? –

+1

うん、 'layoutSubviews'かどこか。レイヤーの階層を変更するのではなく、レンダリングを実際に実行するためにのみ 'draw'をオーバーライドする必要があります。あなたが 'draw'呼び出しの結果としてレイヤーを挿入し、私が見ることができるものを決して削除しないので、あなたは何百ものレイヤーで終わるでしょうか?私は実際にあなたが達成しようとしていることを理解するために苦労している... – Echelon

答えて

1

This commentCALayer mask propertyに は完全にそれを説明する:

マスク層は、下層であるかのようマスクされたレイヤーの座標系に住んでいます。あなたのケースで

、右と下傾斜層の原点を囲むビューの(0, 0)で ないが、(frame.width - width, 0)(frame.height - width, 0)でそれぞれ。 一方、 o shapeMask.pathの点の座標は、囲みビューの(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

これにより問題が解決しました。ありがとうございました! –

関連する問題