- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我使用以下 CAGradientLayer:
let layer = CAGradientLayer()
layer.colors = [
UIColor.redColor().CGColor,
UIColor.greenColor().CGColor,
UIColor.blueColor().CGColor
]
layer.startPoint = CGPointMake(0, 1)
layer.endPoint = CGPointMake(1, 0)
layer.locations = [0.0, 0.6, 1.0]
但是当我为图层设置 bounds 属性时,它只是拉伸(stretch)了一个正方形渐变。我需要像 Sketch 3 应用程序图像中那样的结果(见上文)。
我怎样才能做到这一点?
最佳答案
更新:在 manner similar to the following 中使用 context.drawLinearGradient() 代替 CAGradientLayer .它将绘制与 Sketch/Photoshop 一致的渐变。
如果您绝对必须使用 CAGradientLayer,那么这里是您需要使用的数学...
我花了一些时间才弄明白,但是通过仔细观察,我发现苹果在 CAGradientLayer 中实现的渐变很奇怪:
这意味着中间渐变在新尺寸中将不再形成90度角。这与几乎所有其他绘图应用程序的行为相矛盾:Sketch、Photoshop 等。
如果您想在 Sketch 中实现开始/结束点,您需要转换开始/结束点以说明 Apple 将压缩 View 这一事实。
import UIKit
/// Last updated 4/3/17.
/// See https://stackoverflow.com/a/43176174 for more information.
public enum LinearGradientFixer {
public static func fixPoints(start: CGPoint, end: CGPoint, bounds: CGSize) -> (CGPoint, CGPoint) {
// Naming convention:
// - a: point a
// - ab: line segment from a to b
// - abLine: line that passes through a and b
// - lineAB: line that passes through A and B
// - lineSegmentAB: line segment that passes from A to B
if start.x == end.x || start.y == end.y {
// Apple's implementation of horizontal and vertical gradients works just fine
return (start, end)
}
// 1. Convert to absolute coordinates
let startEnd = LineSegment(start, end)
let ab = startEnd.multiplied(multipliers: (x: bounds.width, y: bounds.height))
let a = ab.p1
let b = ab.p2
// 2. Calculate perpendicular bisector
let cd = ab.perpendicularBisector
// 3. Scale to square coordinates
let multipliers = calculateMultipliers(bounds: bounds)
let lineSegmentCD = cd.multiplied(multipliers: multipliers)
// 4. Create scaled perpendicular bisector
let lineSegmentEF = lineSegmentCD.perpendicularBisector
// 5. Unscale back to rectangle
let ef = lineSegmentEF.divided(divisors: multipliers)
// 6. Extend line
let efLine = ef.line
// 7. Extend two lines from a and b parallel to cd
let aParallelLine = Line(m: cd.slope, p: a)
let bParallelLine = Line(m: cd.slope, p: b)
// 8. Find the intersection of these lines
let g = efLine.intersection(with: aParallelLine)
let h = efLine.intersection(with: bParallelLine)
if let g = g, let h = h {
// 9. Convert to relative coordinates
let gh = LineSegment(g, h)
let result = gh.divided(divisors: (x: bounds.width, y: bounds.height))
return (result.p1, result.p2)
}
return (start, end)
}
private static func unitTest() {
let w = 320.0
let h = 60.0
let bounds = CGSize(width: w, height: h)
let a = CGPoint(x: 138.5, y: 11.5)
let b = CGPoint(x: 151.5, y: 53.5)
let ab = LineSegment(a, b)
let startEnd = ab.divided(divisors: (x: bounds.width, y: bounds.height))
let start = startEnd.p1
let end = startEnd.p2
let points = fixPoints(start: start, end: end, bounds: bounds)
let pointsSegment = LineSegment(points.0, points.1)
let result = pointsSegment.multiplied(multipliers: (x: bounds.width, y: bounds.height))
print(result.p1) // expected: (90.6119039567129, 26.3225059181603)
print(result.p2) // expected: (199.388096043287, 38.6774940818397)
}
}
private func calculateMultipliers(bounds: CGSize) -> (x: CGFloat, y: CGFloat) {
if bounds.height <= bounds.width {
return (x: 1, y: bounds.width/bounds.height)
} else {
return (x: bounds.height/bounds.width, y: 1)
}
}
private struct LineSegment {
let p1: CGPoint
let p2: CGPoint
init(_ p1: CGPoint, _ p2: CGPoint) {
self.p1 = p1
self.p2 = p2
}
init(p1: CGPoint, m: CGFloat, distance: CGFloat) {
self.p1 = p1
let line = Line(m: m, p: p1)
let measuringPoint = line.point(x: p1.x + 1)
let measuringDeltaH = LineSegment(p1, measuringPoint).distance
let deltaX = distance/measuringDeltaH
self.p2 = line.point(x: p1.x + deltaX)
}
var length: CGFloat {
let dx = p2.x - p1.x
let dy = p2.y - p1.y
return sqrt(dx * dx + dy * dy)
}
var distance: CGFloat {
return p1.x <= p2.x ? length : -length
}
var midpoint: CGPoint {
return CGPoint(x: (p1.x + p2.x)/2, y: (p1.y + p2.y)/2)
}
var slope: CGFloat {
return (p2.y-p1.y)/(p2.x-p1.x)
}
var perpendicularSlope: CGFloat {
return -1/slope
}
var line: Line {
return Line(p1, p2)
}
var perpendicularBisector: LineSegment {
let p1 = LineSegment(p1: midpoint, m: perpendicularSlope, distance: -distance/2).p2
let p2 = LineSegment(p1: midpoint, m: perpendicularSlope, distance: distance/2).p2
return LineSegment(p1, p2)
}
func multiplied(multipliers: (x: CGFloat, y: CGFloat)) -> LineSegment {
return LineSegment(
CGPoint(x: p1.x * multipliers.x, y: p1.y * multipliers.y),
CGPoint(x: p2.x * multipliers.x, y: p2.y * multipliers.y))
}
func divided(divisors: (x: CGFloat, y: CGFloat)) -> LineSegment {
return multiplied(multipliers: (x: 1/divisors.x, y: 1/divisors.y))
}
}
private struct Line {
let m: CGFloat
let b: CGFloat
/// y = mx+b
init(m: CGFloat, b: CGFloat) {
self.m = m
self.b = b
}
/// y-y1 = m(x-x1)
init(m: CGFloat, p: CGPoint) {
// y = m(x-x1) + y1
// y = mx-mx1 + y1
// y = mx + (y1 - mx1)
// b = y1 - mx1
self.m = m
self.b = p.y - m*p.x
}
init(_ p1: CGPoint, _ p2: CGPoint) {
self.init(m: LineSegment(p1, p2).slope, p: p1)
}
func y(x: CGFloat) -> CGFloat {
return m*x + b
}
func point(x: CGFloat) -> CGPoint {
return CGPoint(x: x, y: y(x: x))
}
func intersection(with line: Line) -> CGPoint? {
// Line 1: y = mx + b
// Line 2: y = nx + c
// mx+b = nx+c
// mx-nx = c-b
// x(m-n) = c-b
// x = (c-b)/(m-n)
let n = line.m
let c = line.b
if m-n == 0 {
// lines are parallel
return nil
}
let x = (c-b)/(m-n)
return point(x: x)
}
}
我用 View size=320x60
尝试了这个,gradient=[red@0,green@0.5,blue@1]
, startPoint = (0 ,1)
和 endPoint = (1,0)
。
请注意,绿线的角度看起来 100% 准确。区别在于红色和蓝色的混合方式。我不知道这是因为我计算的起点/终点不正确,还是只是 Apple 混合渐变的方式与 Sketch 混合渐变的方式不同。
关于ios - CAGradientLayer 对角渐变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38821631/
ios渐变圆环旋转动画cashapelayer cagradientlayer shape.gif demo.png ?
我正在尝试在 View 上设置渐变背景,但下面的代码使 UIView 显示为纯黑色。如果我将白色更改为绿色,渐变将正确显示。将图层的背景颜色更改为 greenColor 会使 View 显示为纯绿色。
我正在尝试创建一个具有渐变背景的 UITableViewCell。我不明白为什么,但 UITableView 的右侧有一个空白区域。我尝试通过设置纯色但结果没有改变。 这是我的 UITableView
我的问题很简单。 我想使用 CAGradientLayer 为我的 UIView 制作漂亮的渐变背景。 但问题是它显示出丑陋的紫罗兰色,而不是我想要的美妙的红色。 这是我正在使用的代码: - (voi
我使用下面的代码来设置我的 View 的渐变背景颜色。 CAGradientLayer *gradient = [CAGradientLayer layer]; gradient.frame
我正在尝试创建两个渐变层,一个位于 ScrollView 的每一侧,以显示有要滚动到的内容。 左侧的效果很好,但右侧的显示完全透明。我错过了什么? CAGradientLayer *l = [CAGr
好的,我有一个 Collection View 和一个使用 Xib 文件创建的自定义单元格,以便我可以在不同 View 的另一个 Collection View 中使用相同的单元格。在我的 cellF
关于CAGradientLayerlocations属性的文档指定它必须设置为从0到1的NSNumber数组,但它实际上适用于负数和大于1的数字。这样使用安全吗? 它按照您期望的方式工作 gradie
我有以下代码来呈现一个CAGradientLayer,它应该覆盖整个 View 。但是,它在模拟器中显示不正确。我打印了 self.view.bounds.width 和 self.view.boun
您好,我正在尝试从该颜色设置为另一个 View 的渐变中获取颜色。我可以设置开始和结束颜色,但不能设置角度和类型。 以下是值:1.开始颜色:@“2b2b2b”2.结束颜色:@“4a4a4a”3.渐变角
我有一个像 Instagram 个人资料图片中那样的圈子,里面有故事。我想要有一种像圆圈在旋转的感觉。为此,我使用了 CABasicAnimation。它正在旋转,但不在中心。 正如我搜索的那样,我需
我正在使用代码 NSArray *buttons = [NSArray arrayWithObjects: self.rollBtn,nil]; for(UIButton *btn in
我正在为我的 View 背景设置渐变: CAGradientLayer *grad = [CAGradientLayer layer]; grad.frame = self.contentView.f
CAGradientLayer 有两个属性startPoint 和endPoint。这些属性是根据单位坐标空间定义的。结果是,如果我有两个具有相同起点和终点且每个边界不同的渐变层,则这两个渐变将不同。
我用CAShapeLayer画了一个圆,并设置为CAGradientLayer的mask,代码如下: CAShapeLayer *circleShapeLayer = [CAShapelayer ne
我使用 CAGradientLayer 来生成这个细线渐变。问题是自转不顺畅。当 UIViewController 旋转时,我在 viewDidLayoutSubviews 中设置包含该层的 View
我使用 CAGradientLayer 作为按钮的背景。 cell.showOnMap.clipsToBounds = YES; cell.showOnMap.layer.cornerRadius =
我想要一个彩色渐变来覆盖我的 View 。在 View Controller 中,我有这段代码 - (void)viewDidLoad { self.view.backgroundColor =
我想为我的 UIView 创建一个渐变作为背景色。我写了这段代码 gradient.colors = [UIColor.blue,UIColor.yellow] gradient.lo
有一个CAShapeLayer 当我将它添加为 mask 时,我得到一个空白屏幕 这是我的代码: let width: CGFloat = frame.width let radius
我是一名优秀的程序员,十分优秀!