45度の勾配でCAShapeLayer()
をグラデーションで埋めるにはどうすればよいですか?
たとえば、Image 1では、次のコードは正方形を描画し、レイヤーを青で塗りつぶします(UIColor.blueColor().CGColor
)。
しかし、Image 2(つまり、UIColor.blueColor().CGColor
UIColor.redColor().CGColor
)に?
コード:
let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 0, y: 0))
path.addLineToPoint(CGPoint(x: 0, y: 100))
path.addLineToPoint(CGPoint(x: 100, y: 100))
path.addLineToPoint(CGPoint(x: 100, y: 0))
path.closePath()
let shape = CAShapeLayer()
shape.path = path.CGPath
shape.fillColor = UIColor.blueColor().CGColor
CAGradientLayer
およびstartPoint
プロパティを持つendPoint
を使用しないでください。
できるよ:
import UIKit
import PlaygroundSupport
let frame = CGRect(x: 0, y: 0, width: 100, height: 100)
let view = UIView(frame: frame)
PlaygroundPage.current.liveView = view
let path = UIBezierPath(ovalIn: frame)
let shape = CAShapeLayer()
shape.frame = frame
shape.path = path.cgPath
shape.fillColor = UIColor.blue.cgColor
let gradient = CAGradientLayer()
gradient.frame = frame
gradient.colors = [UIColor.blue.cgColor,
UIColor.red.cgColor]
gradient.startPoint = CGPoint(x: 0, y: 1)
gradient.endPoint = CGPoint(x: 1, y: 0)
gradient.mask = shape
view.layer.addSublayer(gradient)
注:正方形のマスクなしで機能するため、円のベジェパスを追加しました。
上記の解決策は実際には45°のような自明な角度でのみ機能しますが、私のコードは任意の角度にグラデーションを設定できます。
public extension CALayer {
public func applyGradient(of colors: UIColor..., atAngle angle: CGFloat) -> CAGradientLayer {
let gradient = CAGradientLayer()
gradient.frame = frame
gradient.colors = colors
gradient.calculatePoints(for: angle)
gradient.mask = self
return gradient
}
}
public extension CAGradientLayer {
/// Sets the start and end points on a gradient layer for a given angle.
///
/// - Important:
/// *0°* is a horizontal gradient from left to right.
///
/// With a positive input, the rotational direction is clockwise.
///
/// * An input of *400°* will have the same output as an input of *40°*
///
/// With a negative input, the rotational direction is clockwise.
///
/// * An input of *-15°* will have the same output as *345°*
///
/// - Parameters:
/// - angle: The angle of the gradient.
///
public func calculatePoints(for angle: CGFloat) {
var ang = (-angle).truncatingRemainder(dividingBy: 360)
if ang < 0 { ang = 360 + ang }
let n: CGFloat = 0.5
let tanx: (CGFloat) -> CGFloat = { tan($0 * CGFloat.pi / 180) }
switch ang {
case 0...45, 315...360:
let a = CGPoint(x: 0, y: n * tanx(ang) + n)
let b = CGPoint(x: 1, y: n * tanx(-ang) + n)
startPoint = a
endPoint = b
case 45...135:
let a = CGPoint(x: n * tanx(ang - 90) + n, y: 1)
let b = CGPoint(x: n * tanx(-ang - 90) + n, y: 0)
startPoint = a
endPoint = b
case 135...225:
let a = CGPoint(x: 1, y: n * tanx(-ang) + n)
let b = CGPoint(x: 0, y: n * tanx(ang) + n)
startPoint = a
endPoint = b
case 225...315:
let a = CGPoint(x: n * tanx(-ang - 90) + n, y: 0)
let b = CGPoint(x: n * tanx(ang - 90) + n, y: 1)
startPoint = a
endPoint = b
default:
let a = CGPoint(x: 0, y: n)
let b = CGPoint(x: 1, y: n)
startPoint = a
endPoint = b
}
}
}
let layer = CAShapeLayer()
// Setup layer...
// Gradient Direction: →
let gradientLayer1 = layer.applyGradient(of: UIColor.yellow, UIColor.red, at: 0)
// Gradient Direction: ↗︎
let gradientLayer2 = layer.applyGradient(of: UIColor.purple, UIColor.yellow, UIColor.green, at: -45)
// Gradient Direction: ←
let gradientLayer3 = layer.applyGradient(of: UIColor.yellow, UIColor.blue, UIColor.green, at: 180)
// Gradient Direction: ↓
let gradientLayer4 = layer.applyGradient(of: UIColor.red, UIColor.blue, at: 450)
だから私は実際、最近自分自身でこれに答えようとすることに多くの時間を費やしました。時計回りの回転方向を理解して視覚化するための角度の例を次に示します。
あなたが私がそれをどのように理解したかに興味があるなら、私は0°-360°。
だと思います
shape.startPoint = CGPoint(x: 1.0, y: 0.0)
shape.endPoint = CGPoint(x: 0.0, y: 1.0)
、これは右下の最初の色から左上にある2番目の色です。右上に最初の色、左下に2番目の色が必要な場合は、
shape.startPoint = CGPoint(x: 1.0, y: 1.0)
shape.endPoint = CGPoint(x: 0.0, y: 0.0)
左上の最初の色、右下の2番目の色
shape.startPoint = NSMakePoint(x: 0.0, y: 1.0)
shape.endPoint = NSMakePoint(x: 1.0, y: 0.0)
左下の最初の色、右上の2番目の色
shape.startPoint = CGPoint(x: 0.0, y: 0.0)
shape.endPoint = CGPoint(x: 1.0, y: 1.0)
@Alistraの回答は、画面の左上隅に形状がある場合に機能します。図形の位置を移動しようとすると、図形が途切れることに気づくでしょう(xとyの値に応じてまったく表示されない場合でも)
これを修正するには、グラデーションレイヤーとシェイプレイヤーの両方に2つの異なるフレームを使用します。シェイプレイヤーのx,y
座標を0,0
に設定します。次に、グラデーションレイヤーのx,y
座標を、画面上の配置したい場所に設定します。
let gradientFrame = CGRect(x: 100,
y: 150,
width: 150,
height: 150)
let circleFrame = CGRect(x: 0,
y: 0,
width: 150,
height: 150)
let circle = CAShapeLayer()
circle.frame = circleFrame
circle.path = UIBezierPath(ovalIn: circleFrame).cgPath
let gradient = CAGradientLayer()
gradient.frame = gradientFrame
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 1)
gradient.colors = [UIColor.blue.cgColor,
UIColor.red.cgColor]
gradient.mask = circle
view.layer.addSublayer(gradient)