gpt4 book ai didi

Add image insde CAShapeLayer(在CAShapeLayer中添加图像)

转载 作者:bug小助手 更新时间:2023-10-25 17:32:19 26 4
gpt4 key购买 nike



So I am currently trying to add a image inside the circularShapeLayer in the below code.

因此,我目前正在尝试在下面的代码中的CircularShapeLayer中添加一个图像。


Here is the full code:

以下是完整的代码:


import Foundation
import UIKit

@IBDesignable
class PlainHorizontalProgressBar: UIView {
@IBInspectable var color: UIColor = .gray {
didSet { setNeedsDisplay() }
}

var progress: CGFloat = 0 {
didSet { setNeedsDisplay() }
}

var circularShapeColor: UIColor = .blue {
didSet { setNeedsDisplay() }
}

private let progressLayer = CALayer()
private let backgroundMask = CAShapeLayer()
private let circularShapeLayer = CAShapeLayer()

// Create an UIImageView for the system image
private let systemImageView = UIImageView()

override init(frame: CGRect) {
super.init(frame: frame)
circularShapeColor = UIColor.systemOrange
setupLayers()
}

required init?(coder: NSCoder) {
super.init(coder: coder)
circularShapeColor = UIColor.systemOrange
setupLayers()
}

private func setupLayers() {
layer.addSublayer(progressLayer)
layer.addSublayer(circularShapeLayer)

// Add the system image view to the circularShapeLayer
circularShapeLayer.addSublayer(systemImageView.layer)
}

override func draw(_ rect: CGRect) {
backgroundMask.path = UIBezierPath(roundedRect: rect, cornerRadius: rect.height * 0.75).cgPath
layer.mask = backgroundMask

let progressRect = CGRect(origin: .zero, size: CGSize(width: rect.width * progress, height: rect.height))

progressLayer.frame = progressRect
progressLayer.backgroundColor = color.cgColor

// Calculate the position and size of the circular shape
let circularSize = CGSize(width: rect.height, height: rect.height)
let circularOrigin = CGPoint(x: progressRect.maxX - circularSize.width / 2.0, y: (rect.height - circularSize.height) / 2.0)
let circularPath = UIBezierPath(ovalIn: CGRect(origin: circularOrigin, size: circularSize))
circularShapeLayer.path = circularPath.cgPath

// Set the frame and image for the system image view
systemImageView.frame = circularShapeLayer.bounds
systemImageView.image = UIImage(systemName: "bolt.fill") // Set the system image
systemImageView.tintColor = .white // Set the image color
}
}

But somehow the image is not showing. I have tried changing the tintColor of the image, and tried with other images also. What am I doing wrong? Any suggestions or ideas on how can I accomplish this?

但不知何故,图像并没有显示出来。我已经尝试更改图像的tintColor,也尝试了其他图像。我做错了什么?我如何才能做到这一点有什么建议或想法吗?


更多回答

Using layers, you don't need to override draw() ... it would be helpful if you show us a pic of how you want it to look.

使用层,您不需要重写DRAW()...如果你给我们看一张你希望它看起来是什么样子的照片,那将是很有帮助的。

Are you trying to get something like this? i.stack.imgur.com/Y7t0h.png ... top one has Height: 60 -- bottom one has Height: 30

你想得到这样的东西吗?i.stack.imgur.com/Y7t0h.png.顶部的高度:60 -底部的高度:30

@DonMag Yes, like that image.

@DonMag是的,喜欢这张照片。

优秀答案推荐

Instead of overriding draw(_:), let's manipulate layers.

让我们操作层,而不是覆盖DRAW(_:)。


First note... we probably don't want to mask the "base layer" (the entire view) because we might want to - at some point - "fancy it up" a little bit.

第一个音符...我们可能不想屏蔽“基础层”(整个视图),因为我们可能想--在某个时刻--稍微“想象一下”。


And, for example, we would want:

例如,我们希望:


enter image description here


So let's use:

因此,让我们使用:


private let backgroundLayer = CALayer()
private let backgroundMaskLayer = CAShapeLayer()
private let progressLayer = CALayer()

// Create an UIImageView for the system image
private let systemImageView = UIImageView()

and we will add progressLayer as a sublayer of backgroundLayer, then mask the backgroundLayer.

我们将添加ProgressLayer作为BackekLayer的子层,然后遮罩BackekLayer。


We'll also add systemImageView as a subview instead of a layer.

我们还将添加system ImageView作为子视图,而不是层。


We'll do the main setup like this:

我们将像这样进行主要设置:


private func setupLayers() {

layer.addSublayer(backgroundLayer)
backgroundLayer.addSublayer(progressLayer)
backgroundLayer.mask = backgroundMaskLayer

backgroundLayer.backgroundColor = baseColor.cgColor

systemImageView.image = UIImage(systemName: "bolt.fill") // Set the system image
systemImageView.tintColor = .white // Set the image color

addSubview(systemImageView)

backgroundColor = .clear

}

Instead of overriding draw(_:) we'll update everything in layoutSubviews():

我们将更新layoutSubview()中的所有内容,而不是覆盖DRAW(_:):


override func layoutSubviews() {
super.layoutSubviews()

// colors may have been changed after init
backgroundLayer.backgroundColor = baseColor.cgColor
progressLayer.backgroundColor = color.cgColor
systemImageView.backgroundColor = circularShapeColor

backgroundLayer.frame = bounds
backgroundMaskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: bounds.height * 0.75).cgPath

let progressRect = CGRect(origin: .zero, size: CGSize(width: bounds.width * progress, height: bounds.height))
progressLayer.frame = progressRect

// Calculate the position and size of the circular shape

let w: CGFloat = bounds.height
let circularSize = CGSize(width: w, height: w)

let circularOrigin = CGPoint(x: progressRect.maxX - w / 2.0, y: progressRect.midY - (w / 2.0))

// Set the frame and image for the system image view
systemImageView.frame = .init(origin: circularOrigin, size: circularSize)
systemImageView.layer.cornerRadius = w * 0.5
}

That will give us this:

这将给我们带来这样的结果:


enter image description here


and we're looking pretty good.

我们看起来很不错。


Except... if we're close to 0% or 100% the position of the circular-view won't look great:

除了..。如果我们接近0%或100%,圆形视图的位置看起来不会很好:


enter image description here


We'll "fix" that...

我们会“修复”它的..。


Let's calculate the "progress range" - inset on each end by one-half of the circular-view width:

让我们计算“进度范围”--两端插入圆形视图宽度的一半:


enter image description here


and modify our positioning calculations:

并修改我们的定位计算:


    let w: CGFloat = bounds.height
let circularSize = CGSize(width: w, height: w)

// we want 0% to have the circle-image center at leading Plus one-half circle-width
// we want 100% to have the circle-image center at trailing Minus one-half circle-width
let progressRange: CGFloat = (bounds.width - w)

// calculate the circle-image centerX
let circleCenterX: CGFloat = w * 0.5 + progressRange * progress

let progressRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: circleCenterX, height: bounds.height))

progressLayer.frame = progressRect

let circularOrigin = CGPoint(x: circleCenterX - w / 2.0, y: progressRect.midY - (w / 2.0))

// Set the frame for the system image view
systemImageView.frame = CGRect(origin: circularOrigin, size: circularSize)


and it's looking better:

而且它看起来更好了:


enter image description here


Here's your complete class, with all of those modifications:

下面是您的完整类,其中包含所有这些修改:


@IBDesignable
class PlainHorizontalProgressBar: UIView {

@IBInspectable
// default: very light gray
var baseColor: UIColor = UIColor(white: 0.9, alpha: 1.0) {
didSet { setNeedsLayout() }
}

@IBInspectable
// default: gray
var color: UIColor = .gray {
didSet { setNeedsLayout() }
}

@IBInspectable
// default: orange
var circularShapeColor: UIColor = .orange {
didSet { setNeedsLayout() }
}

@IBInspectable
// default: 0.0
var progress: CGFloat = 0.0 {
didSet { setNeedsLayout() }
}

private let backgroundLayer = CALayer()
private let backgroundMaskLayer = CAShapeLayer()

private let progressLayer = CALayer()

// Create an UIImageView for the system image
private let systemImageView = UIImageView()

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

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

private func setupLayers() {

layer.addSublayer(backgroundLayer)
backgroundLayer.addSublayer(progressLayer)
backgroundLayer.mask = backgroundMaskLayer

backgroundLayer.backgroundColor = baseColor.cgColor

systemImageView.image = UIImage(systemName: "bolt.fill") // Set the system image
systemImageView.tintColor = .white // Set the image color

addSubview(systemImageView)

backgroundColor = .clear

}

override func layoutSubviews() {
super.layoutSubviews()

// colors may have been changed after init
backgroundLayer.backgroundColor = baseColor.cgColor
progressLayer.backgroundColor = color.cgColor
systemImageView.backgroundColor = circularShapeColor

backgroundLayer.frame = bounds
backgroundMaskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: bounds.height * 0.75).cgPath

// Calculate the position and size of the circular shape

let w: CGFloat = bounds.height
let circularSize = CGSize(width: w, height: w)

// we want 0% to have the circle-image center at leading Plus one-half circle-width
// we want 100% to have the circle-image center at trailing Minus one-half circle-width
let progressRange: CGFloat = (bounds.width - w)

// calculate the circle-image centerX
let circleCenterX: CGFloat = w * 0.5 + progressRange * progress

let progressRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: circleCenterX, height: bounds.height))

progressLayer.frame = progressRect

let circularOrigin = CGPoint(x: circleCenterX - w / 2.0, y: progressRect.midY - (w / 2.0))

// Set the frame for the system image view
systemImageView.frame = CGRect(origin: circularOrigin, size: circularSize)

// let's use .layer.cornerRadius instead of another layer mask
systemImageView.layer.cornerRadius = systemImageView.frame.width * 0.5

}

}



Edit

编辑


If you want the "circular view" to be larger than the "progress bar" (as in the first image I posted)...

如果你想让“圆形视图”比“进度条”大(就像我发布的第一张图片一样).


In layoutSubviews() change:

在layoutSubview()中更改:


    backgroundLayer.frame = bounds
backgroundMaskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: bounds.height * 0.75).cgPath

to:

致:


    backgroundLayer.frame = bounds
let r: CGRect = bounds.insetBy(dx: 0.0, dy: bounds.height * 0.25)
backgroundMaskLayer.path = UIBezierPath(roundedRect: r, cornerRadius: r.height * 0.5).cgPath

That will make the "bar height" one-half of the view height, centered vertically.

这将使“条形高度”为视图高度的一半,垂直居中。



A couple of things:

有几件事:


Don't override draw(_:) if you're constructing a view out of layers.

如果你在层外构造视图,不要覆盖draw(_:)。


You can't install a view's content layer as a sublayer of another layer. Use primitive layers. You can install an image as the contents of a "regular" CALayer, and then install that layer as a sublayer of your shape layer. That would work.

不能将视图的内容层安装为另一个层的子层。使用基本层。您可以将图像安装为“常规”CALayer的内容,然后将该层安装为Shape Layer的子层。这会奏效的。


更多回答

Wow, thanks you so much! Very cell explained. I really liked this: i.stack.imgur.com/gdMl7.png. Is it possible to edit the code so the bolt circle is bigger than the progress view like the image?

哇,太感谢你了!非常细胞解释说。我真的很喜欢这个:i.stack.imgur.com/gdMl7.png。是否可以编辑代码,使螺栓圆大于进度视图(如图像)?

@Saland - see the Edit at the bottom of my answer.

@Saland-请参阅我答案底部的编辑。

Again, thank you so much! I really appreciate that you actually take your time to explain the code also, and the steps. +1 to you.

再次,非常感谢你们!我真的很感激你花时间来解释代码和步骤。加1给你。

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