Угловой градиент можно получить, используя базовую тригонометрию. Вы можете добиться этого, создав подкласс UIView, как я описал в своем сообщении в блоге по этому вопросу а>.
Сначала определите некоторые переменные: -
// The end point of the gradient when drawn in the layer’s coordinate space. Animatable.
var endPoint: CGPoint
// The start point of the gradient when drawn in the layer’s coordinate space. Animatable.
var startPoint: CGPoint
// the gradient angle, in degrees anticlockwise from 0 (east/right)
@IBInspectable var angle: CGFloat = 270
Основная функция, показанная ниже, получает начальную и конечную точки в единичном пространстве.
// create vector pointing in direction of angle
private func gradientPointsForAngle(_ angle: CGFloat) -> (CGPoint, CGPoint) {
// get vector start and end points
let end = pointForAngle(angle)
let start = oppositePoint(end)
// convert to gradient space
let p0 = transformToGradientSpace(start)
let p1 = transformToGradientSpace(end)
return (p0, p1)
}
Это просто берет угол, указанный пользователем, и использует его для создания вектора, указывающего в этом направлении. Угол определяет поворот вектора от 0 градусов, который по соглашению указывает на восток в Core Animation, и увеличивается против часовой стрелки (против часовой стрелки).
Остальная часть соответствующего кода приведена ниже и касается того факта, что результирующая точка находится на единичной окружности. Однако нужные нам точки находятся в единичном квадрате: вектор экстраполируется на единичный квадрат.
private func pointForAngle(_ angle: CGFloat) -> CGPoint {
// convert degrees to radians
let radians = angle * .pi / 180.0
var x = cos(radians)
var y = sin(radians)
// (x,y) is in terms unit circle. Extrapolate to unit square to get full vector length
if (fabs(x) > fabs(y)) {
// extrapolate x to unit length
x = x > 0 ? 1 : -1
y = x * tan(radians)
} else {
// extrapolate y to unit length
y = y > 0 ? 1 : -1
x = y / tan(radians)
}
return CGPoint(x: x, y: y)
}
private func oppositePoint(_ point: CGPoint) -> CGPoint {
return CGPoint(x: -point.x, y: -point.y)
}
private func transformToGradientSpace(_ point: CGPoint) -> CGPoint {
// input point is in signed unit space: (-1,-1) to (1,1)
// convert to gradient space: (0,0) to (1,1), with flipped Y axis
return CGPoint(x: (point.x + 1) * 0.5, y: 1.0 - (point.y + 1) * 0.5)
}
И в конечном итоге все должно вызываться из функции обновления:
private func updateGradient() {
if let gradient = self.gradient {
let (start, end) = gradientPointsForAngle(self.angle)
gradient.startPoint = start
gradient.endPoint = end
gradient.frame = self.bounds
}
}
Полную реализацию см. в моем сообщении в блоге.
person
Echelon
schedule
25.09.2018