I have some strange behaviour of CAEmitterCell color property or I don't understand it right.
I have a cell
let cell = CAEmitterCell()
With content of simple .png file which is drawn black
cell.contents = UIImage(named: "particle")?.cgImage
And I try to change it to green
cell.color = UIColor.green.cgColor
But it is still rendered black.
I tried to change "Render as" property of this image to "Template imagr" in media asset but it has no effect.
Can anyone help me to understand what I'm doing wrong?
Ok, the case was the color of initial image: the darker the image - the less color variation you have. So better use white images for your particle emitters %)
This is simple example how you can change color of the CAEmitterCell.
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
createParticles()
}
func createParticles() {
let particleEmitter = CAEmitterLayer()
particleEmitter.emitterPosition = CGPoint(x: view.center.x, y: -96)
particleEmitter.emitterShape = kCAEmitterLayerLine
particleEmitter.emitterSize = CGSize(width: view.frame.size.width, height: 1)
let red = makeEmitterCell(color: UIColor.red)
let green = makeEmitterCell(color: UIColor.green)
let blue = makeEmitterCell(color: UIColor.blue)
particleEmitter.emitterCells = [red, green, blue]
view.layer.addSublayer(particleEmitter)
}
func makeEmitterCell(color: UIColor) -> CAEmitterCell {
let cell = CAEmitterCell()
cell.birthRate = 3
cell.lifetime = 7.0
cell.lifetimeRange = 0
cell.color = color.cgColor
cell.velocity = 200
cell.velocityRange = 50
cell.emissionLongitude = CGFloat.pi
cell.emissionRange = CGFloat.pi / 4
cell.spin = 2
cell.spinRange = 3
cell.scaleRange = 0.5
cell.scaleSpeed = -0.05
cell.contents = UIImage(named: "images")?.cgImage
return cell
}
}
And example of the animation.
Related
I'm a beginner in swift. I want to draw a shadow behind my View in a UITableViewCell but when I add the following code :
func doTheWork(statutOfCard : statut){
switch statutOfCard {
case .selectPicture:
cardViewHeightCon.constant = 300
if ShadowLayerCard == nil{
self.addCardShadow()
}
case .modifyPicture:
cardViewHeightCon.constant = 400
if ShadowLayerCard == nil{
self.addCardShadow()
}
default:
cardViewHeightCon.constant = 300
if ShadowLayerCard == nil{
self.addCardShadow()
}
}
}
func addCardShadow(){
let shadowLayer = CAShapeLayer()
ShadowLayerCard = shadowLayer
shadowLayer.path = UIBezierPath(roundedRect: CGRect(0, 0, widthOfDevice! - (widthMarginConstraint*2), cardViewHeightCon.constant), cornerRadius: 10).cgPath
shadowLayer.fillColor = UIColor(rgb: 0x00ff33).cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowRadius = 5
shadowLayer.shadowOpacity = 0.2
shadowLayer.shadowOffset = CGSize(width: 0, height: 0)
cardView.layer.insertSublayer(shadowLayer, at: 0)
}
the shadow appears in the UITableViewCell but when I scroll down, this produces a visual bug like this:
I think that the shadow is drawn before the height of the cardView was updated, but how can I fix this problem? And if I need to add another component like a picture programmatically, can I write this in the doTheWork function? Or will this produce a bug again?
Add shadow to cardView.layer and do it once when the cell created. You might need another view to hold your image with rounded corners, because you will need to set clip to bound true for corners.
func addCardShadow(){
let shadowLayer = cardView.layer
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowRadius = 5
shadowLayer.shadowOpacity = 0.2
shadowLayer.shadowOffset = CGSize(width: 2, height: 2)
}
I am attempting to do something that I thought would be possible, but have no idea how to start.
I have created a UIView and would like it to be filled with colour, but in the shape defined by an image mask. i.e. I have a PNG with alpha, and I would like the UIView I have created to be UIColor.blue in the shape of that PNG.
To show just how stupid I am, here is the absolute rubbish I have attempted so far - trying to generate just a simple square doesn't even work for me, hence it's all commented out.
let rocketColourList: [UIColor] = [UIColor.blue, UIColor.red, UIColor.green, UIColor.purple, UIColor.orange]
var rocketColourNum: Int = 0
var rocketAngleNum: Int = 0
var rocketAngle: Double {
return Double(rocketAngleNum) * Double.pi / 4
}
var rocketColour = UIColor.black
public func drawRocket (){
rocketColour.set()
self.clipsToBounds = true
self.backgroundColor = UIColor.red
imageView.image = UIImage(named: ("rocketMask"))
addSubview(imageView)
//maskimage.frame = self.frame
//let someRect = CGRect (x: 1, y: 1, width: 1000, height: 1000)
//let someRect = CGRect (self.frame)
//let fillPath = UIBezierPath(rect:someRect)
//fillPath.fill()
//setNeedsDisplay()
}
}
Set image as template, then set tint color for UIImageView. Something like that:
guard let let image = UIImage(named: "rocketMask")?.withRenderingMode(.alwaysTemplate) else { return }
imageView.image = image
imageView.tintColor = .blue
Also you can do that through the images assets:
I have a UITextField with two CAShapeLayers. I want to have my text always centered and limited (in size) to the inner, white circle.
How can I limit the size of the text within that white circle, best with a padding, but also make the text always fill that space? The second part prob has something to do with a scaling factor which sets the text font size smaller, if there is more text.
Here is my MWE:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .darkGray
let size:CGFloat = 300.0
let centerPoint:CGFloat = 200.0
let valueLabel = UITextField()
valueLabel.isUserInteractionEnabled = false
valueLabel.contentVerticalAlignment = .center
valueLabel.textAlignment = .center
valueLabel.text = "300"
valueLabel.textColor = .black
valueLabel.font = UIFont.init(name: "HelveticaNeue-Medium", size: 100)
valueLabel.bounds = CGRect(x:0.0, y:0.0, width:size, height:size)
valueLabel.center = CGPoint(x:centerPoint, y:centerPoint)
let redCircle:CAShapeLayer = CAShapeLayer()
redCircle.path = UIBezierPath(ovalIn: valueLabel.bounds).cgPath
redCircle.fillColor = UIColor.red.cgColor
redCircle.strokeColor = UIColor.white.cgColor
redCircle.lineWidth = 10
valueLabel.layer.addSublayer(redCircle)
let whiteCircle:CAShapeLayer = CAShapeLayer()
let tmpRect = CGRect(x:valueLabel.bounds.origin.x,y:valueLabel.bounds.origin.x,width:valueLabel.bounds.width-80.0,height:valueLabel.bounds.height-80.0)
whiteCircle.path = UIBezierPath(ovalIn: tmpRect).cgPath
whiteCircle.fillColor = UIColor.white.cgColor
whiteCircle.strokeColor = UIColor.white.cgColor
whiteCircle.lineWidth = 10
let posX = valueLabel.bounds.midX - (size-80.0)/2.0
let posY = valueLabel.bounds.midY - (size-80.0)/2.0
whiteCircle.position = CGPoint(x:posX, y:posY)
valueLabel.layer.addSublayer(whiteCircle)
self.view.addSubview(valueLabel)
}
}
For that purpose I can suggest using UITextView, it has native support for that via NSTextContainer. docs
textView.textContainer.exclusionPaths = [..] // array of UIBezierPaths
You can try
valueLabel.adjustsFontSizeToFitWidth = true
valueLabel.minimumFontSize = 0.5
I hope that would be useful for you.
I have a moving black image on a dark screen, to make it easier to see I would like to add in a white glow to the image. This is my code for the moving image:
Ghost = SKSpriteNode(imageNamed: "Ghost1")
Ghost.size = CGSize(width: 50, height: 50)
Ghost.position = CGPoint(x: self.frame.width / 2 - Ghost.frame.width, y: self.frame.height / 2)
Ghost.physicsBody = SKPhysicsBody(circleOfRadius: Ghost.frame.height / 1.4)
Ghost.physicsBody?.categoryBitMask = PhysicsCatagory.Ghost
Ghost.physicsBody?.collisionBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall
Ghost.physicsBody?.contactTestBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall | PhysicsCatagory.Score
Ghost.physicsBody?.affectedByGravity = false
Ghost.physicsBody?.isDynamic = true
Ghost.zPosition = 2
self.addChild(Ghost)
I'm not sure how or what to use to add in a glow, if you need more information please ask.
I created this extension to add a glow effect to an SKSpriteNode
Just add this to your project
extension SKSpriteNode {
func addGlow(radius: Float = 30) {
let effectNode = SKEffectNode()
effectNode.shouldRasterize = true
addChild(effectNode)
let effect = SKSpriteNode(texture: texture)
effect.color = self.color
effect.colorBlendFactor = 1
effectNode.addChild(effect)
effectNode.filter = CIFilter(name: "CIGaussianBlur", parameters: ["inputRadius":radius])
}
}
Now given an SKSpriteNode
let sun = SKSpriteNode(imageNamed: "sun")
all you have to do it
sun.addGlow()
Just to add to this, you can perform this on any type of SKNode by first rendering its contents using the texture(from:SKNode) method available on an SKView instance.
Example:
extension SKNode
{
func addGlow(radius:CGFloat=30)
{
let view = SKView()
let effectNode = SKEffectNode()
let texture = view.texture(from: self)
effectNode.shouldRasterize = true
effectNode.filter = CIFilter(name: "CIGaussianBlur",withInputParameters: ["inputRadius":radius])
addChild(effectNode)
effectNode.addChild(SKSpriteNode(texture: texture))
}
}
I have a moving black image on a dark screen, to make it easier to see I would like to add in a white glow to the image. This is my code for the moving image:
Ghost = SKSpriteNode(imageNamed: "Ghost1")
Ghost.size = CGSize(width: 50, height: 50)
Ghost.position = CGPoint(x: self.frame.width / 2 - Ghost.frame.width, y: self.frame.height / 2)
Ghost.physicsBody = SKPhysicsBody(circleOfRadius: Ghost.frame.height / 1.4)
Ghost.physicsBody?.categoryBitMask = PhysicsCatagory.Ghost
Ghost.physicsBody?.collisionBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall
Ghost.physicsBody?.contactTestBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall | PhysicsCatagory.Score
Ghost.physicsBody?.affectedByGravity = false
Ghost.physicsBody?.isDynamic = true
Ghost.zPosition = 2
self.addChild(Ghost)
I'm not sure how or what to use to add in a glow, if you need more information please ask.
I created this extension to add a glow effect to an SKSpriteNode
Just add this to your project
extension SKSpriteNode {
func addGlow(radius: Float = 30) {
let effectNode = SKEffectNode()
effectNode.shouldRasterize = true
addChild(effectNode)
let effect = SKSpriteNode(texture: texture)
effect.color = self.color
effect.colorBlendFactor = 1
effectNode.addChild(effect)
effectNode.filter = CIFilter(name: "CIGaussianBlur", parameters: ["inputRadius":radius])
}
}
Now given an SKSpriteNode
let sun = SKSpriteNode(imageNamed: "sun")
all you have to do it
sun.addGlow()
Just to add to this, you can perform this on any type of SKNode by first rendering its contents using the texture(from:SKNode) method available on an SKView instance.
Example:
extension SKNode
{
func addGlow(radius:CGFloat=30)
{
let view = SKView()
let effectNode = SKEffectNode()
let texture = view.texture(from: self)
effectNode.shouldRasterize = true
effectNode.filter = CIFilter(name: "CIGaussianBlur",withInputParameters: ["inputRadius":radius])
addChild(effectNode)
effectNode.addChild(SKSpriteNode(texture: texture))
}
}