gpt4 book ai didi

ios - 径向 CAGradientLayer 在运行时无法正确渲染

转载 作者:行者123 更新时间:2023-11-28 13:28:37 34 4
gpt4 key购买 nike

我正在尝试快速创建一个径向 CAGradientLayer。普通 CAGradientLayers(默认类型 axial)没有问题。它们在模拟器中的快照和运行时呈现良好。

当我拍摄我创建的 UIView 的快照时(仅针对 CAGradientLayer),它显示了一个漂亮的径向 CAGradientLayer。但是,当我使用这个 View 并在运行时在模拟器中查看它时,它看起来很糟糕。我不知道我做错了什么。

这是 CAGradientLayer 的代码:

import Foundation

class ChannelGradientView: UIView {

// MARK: - Init

override init(frame: CGRect) {
super.init(frame: frame)
setup()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}

// MARK: - Setup

private func setup() {
backgroundColor = .clear
setupGradient()
}

private func setupGradient() {
let gradient = layer as? CAGradientLayer
gradient?.type = .radial

gradient?.colors = [
UIColor.black.withAlphaComponent(0.8),
UIColor.black.withAlphaComponent(0)
].map { $0.cgColor }

let blackPoint = CGPoint(x: 1, y: 0)
let clearPoint = CGPoint(x: 1, y: 1)

// startpoint is center (for example black here)
gradient?.startPoint = blackPoint
gradient?.endPoint = clearPoint
}

// MARK: - Layer

override public class var layerClass: Swift.AnyClass {
return CAGradientLayer.self
}
}

这是我进行快照单元测试时的样子(使用 Nimble Snapshot 库):

enter image description here

这是它在模拟器上运行时的样子:

enter image description here enter image description here

有人知道我做错了什么吗?

编辑:在实际设备上运行时,它甚至不显示任何渐变层,即使是糟糕的层也不行。这是一个透明的盒子。

最佳答案

不确定您在模拟器和设备上看到的内容之间还发生了什么,但是...

如果我按原样使用您的代码,我会得到这个(红色边框显示框架):

enter image description here

如果我改变你的clearPoint:

//let clearPoint = CGPoint(x: 1, y: 1)
let clearPoint = CGPoint(x: 0, y: 1) // bottom-left-corner

我明白了:

enter image description here

模拟器和设备上的外观相同


编辑

一些额外的说明...

径向渐变不像.axial(线性)渐变那样使用.startPoint.endPoint

.radial绘制一个渐变*椭圆,以.startPoint为中心,startPoint的区别.xendPoint.x 乘以 2 作为其宽度,startPoint.yendPoint.y 之间的差异乘以 2 作为它的高度。

因此,要获得所需的从右上角到左下角的径向渐变,您需要将 .startPoint 设置为 1,0。 endPoint 到导致大小为 2 x 2 的渐变椭圆的值:

startPoint = 1,0

endPoint = 0,1

width: abs(1 - 0) * 2 = 2
height: abs(0 - 1) * 2 = 2

请注意,您可以通过以下方式获得相同的结果:

startPoint = 1,0

endPoint = 2,-1

width: abs(1 - 2) * 2 = 2
height: abs(0 - (-1)) * 2 = 2

.radial 渐变 喜欢的是将其宽度或高度设置为零,这正是我们得到的:

startPoint = 1,0

endPoint = 1,1

width: abs(1 - 1) * 2 = 0 // problem!!!!
height: abs(0 - 1) * 2 = 2

如我们所见,结果是奇怪的线条图案。

这里有一些实际的例子来演示。

轴向/线性右上到左下:

enter image description here

径向居中且宽度= View 宽度/高度= View 高度:

enter image description here

径向居中且宽度=二分之一 View 宽度/高度= View 高度:

enter image description here

径向居中和宽度 = 二分之一 View 宽度/高度 = View 高度...完全相同的结果,但请注意 .endPoint.x 值为 0.75而不是 0.25:

enter image description here

现在我们改变 .startPoint.x = 0.75,但是我们保留 .endPoint.x = 0.25,所以椭圆的中心移动到 3/4ths View 的宽度,但椭圆的宽度变得等于 View 的宽度... abs(0.75 - 0.25) * 2 == 1.0:

enter image description here

更改 .endPoint.x = 0.5 并且宽度返回到 View 宽度的 1/2... abs(0.75 - 0.5) * 2 = 0.5 :

enter image description here

最后是从右上角到左下角的径向渐变:

enter image description here

这是我用来生成这些图像的代码。它有一个“梯度定义”的数据 block ......您可以添加/更改这些定义以试验差异。

//
// GradTestViewController.swift
//
// Created by Don Mag on 9/12/19.
//

import UIKit

class TestGradientView: UIView {

// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}

// MARK: - Setup
private func setup() {

// just set the background to clear and the
// gradient colors to blue -> green
backgroundColor = .clear

if let gradient = layer as? CAGradientLayer {
gradient.colors = [
UIColor.blue,
UIColor.green,
].map { $0.cgColor }
}

}

// MARK: - Layer
override public class var layerClass: Swift.AnyClass {
return CAGradientLayer.self
}

}

struct GradDef {
var gradType: CAGradientLayerType = .axial
var startPoint: CGPoint = CGPoint(x: 1.0, y: 0.0)
var endPoint: CGPoint = CGPoint(x: 0.0, y: 1.0)
}

class GradTestViewController: UIViewController {

var theButton: UIButton = {
let v = UIButton()
v.setTitle("Tap", for: .normal)
v.setTitleColor(.white, for: .normal)
v.setTitleColor(.lightGray, for: .highlighted)
v.backgroundColor = .red
return v
}()

var counterLabel: UILabel = {
let v = UILabel()
return v
}()

var descLabel: UILabel = {
let v = UILabel()
v.numberOfLines = 0
return v
}()

var gradContainerView: UIView = {
let v = UIView()
return v
}()

var gradView: TestGradientView = {
let v = TestGradientView()
return v
}()

var tlLabel: UILabel = {
let v = UILabel()
v.text = "0,0"
return v
}()

var trLabel: UILabel = {
let v = UILabel()
v.text = "1,0"
return v
}()

var blLabel: UILabel = {
let v = UILabel()
v.text = "0,1"
return v
}()

var brLabel: UILabel = {
let v = UILabel()
v.text = "1,1"
return v
}()

var theStackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.alignment = .center
v.distribution = .fill
v.spacing = 20.0
return v
}()

var gradDefs: [GradDef] = [
GradDef(gradType: .axial, startPoint: CGPoint(x: 1.0, y: 0.0), endPoint: CGPoint(x: 0.0, y: 1.0)),
GradDef(gradType: .radial, startPoint: CGPoint(x: 0.5, y: 0.5), endPoint: CGPoint(x: 0.0, y: 0.0)),
GradDef(gradType: .radial, startPoint: CGPoint(x: 0.5, y: 0.5), endPoint: CGPoint(x: 0.25, y: 0.0)),
GradDef(gradType: .radial, startPoint: CGPoint(x: 0.5, y: 0.5), endPoint: CGPoint(x: 0.75, y: 0.0)),
GradDef(gradType: .radial, startPoint: CGPoint(x: 0.75, y: 0.5), endPoint: CGPoint(x: 0.25, y: 0.0)),
GradDef(gradType: .radial, startPoint: CGPoint(x: 0.75, y: 0.5), endPoint: CGPoint(x: 1.0, y: 0.0)),
GradDef(gradType: .radial, startPoint: CGPoint(x: 1.0, y: 0.0), endPoint: CGPoint(x: 0.0, y: 1.0)),
]

var idx: Int = 0

override func viewDidLoad() {
super.viewDidLoad()

[theButton, counterLabel, gradContainerView, gradView, tlLabel, trLabel, blLabel, brLabel, descLabel, theStackView].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}

[theButton, counterLabel, gradContainerView, descLabel].forEach {
theStackView.addArrangedSubview($0)
}

[gradView, tlLabel, trLabel, blLabel, brLabel].forEach {
gradContainerView.addSubview($0)
}

[counterLabel, tlLabel, trLabel, blLabel, brLabel, descLabel].forEach {
$0.font = UIFont.monospacedDigitSystemFont(ofSize: 14.0, weight: .regular)
}

NSLayoutConstraint.activate([

gradView.widthAnchor.constraint(equalToConstant: 120),
gradView.heightAnchor.constraint(equalTo: gradView.widthAnchor),
gradView.centerXAnchor.constraint(equalTo: gradContainerView.centerXAnchor),
gradView.centerYAnchor.constraint(equalTo: gradContainerView.centerYAnchor),

tlLabel.centerXAnchor.constraint(equalTo: gradView.leadingAnchor, constant: 0.0),
blLabel.centerXAnchor.constraint(equalTo: gradView.leadingAnchor, constant: 0.0),
trLabel.centerXAnchor.constraint(equalTo: gradView.trailingAnchor, constant: 0.0),
brLabel.centerXAnchor.constraint(equalTo: gradView.trailingAnchor, constant: 0.0),

tlLabel.bottomAnchor.constraint(equalTo: gradView.topAnchor, constant: -2.0),
trLabel.bottomAnchor.constraint(equalTo: gradView.topAnchor, constant: -2.0),

blLabel.topAnchor.constraint(equalTo: gradView.bottomAnchor, constant: 2.0),
brLabel.topAnchor.constraint(equalTo: gradView.bottomAnchor, constant: 2.0),

tlLabel.topAnchor.constraint(equalTo: gradContainerView.topAnchor, constant: 4.0),
tlLabel.leadingAnchor.constraint(equalTo: gradContainerView.leadingAnchor, constant: 4.0),

brLabel.trailingAnchor.constraint(equalTo: gradContainerView.trailingAnchor, constant: -4.0),
brLabel.bottomAnchor.constraint(equalTo: gradContainerView.bottomAnchor, constant: -4.0),

])

view.addSubview(theStackView)

NSLayoutConstraint.activate([

theStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40.0),
theStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),

theButton.widthAnchor.constraint(equalToConstant: 160.0),
descLabel.widthAnchor.constraint(equalToConstant: 240.0),

])

theButton.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)

idx = -1
didTap(nil)
}

@IBAction func didTap(_ sender: Any?) {

guard let gLayer = gradView.layer as? CAGradientLayer else {
fatalError("Could not get the gradient layer!")
}

idx += 1

if idx >= gradDefs.count {
idx = 0
}

let gDef = gradDefs[idx]

gLayer.type = gDef.gradType
gLayer.startPoint = gDef.startPoint
gLayer.endPoint = gDef.endPoint

var s = ""
s += "Gradient Type: " + (gDef.gradType == CAGradientLayerType.axial ? "Axial" : "Radial")
s += "\n\n"
s += "Start Point: \(gDef.startPoint)"
s += "\n"
s += "End Point: \(gDef.endPoint)"

if gDef.gradType == CAGradientLayerType.radial {
let w = abs(gDef.startPoint.x - gDef.endPoint.x) * 2
let h = abs(gDef.startPoint.y - gDef.endPoint.y) * 2
s += "\n\n"
s += "\t" + "Radial Width:"
s += "\n"
s += "\t\t" + "abs(\(gDef.startPoint.x) - \(gDef.endPoint.x)) * 2 == \(w)"
s += "\n\n"
s += "\t" + "Radial Height:"
s += "\n"
s += "\t\t" + "abs(\(gDef.startPoint.y) - \(gDef.endPoint.y)) * 2 == \(h)"
}

s += "\n"

descLabel.text = s

counterLabel.text = "Variation \(idx + 1) of \(gradDefs.count)"

}

}

一切都在代码中完成 - 没有 @IBOutlets@IBActions,所以只需创建一个新的 View Controller 并将其自定义类分配给 GradTestViewController .

关于ios - 径向 CAGradientLayer 在运行时无法正确渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57889427/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com