'Sparkle effect iOS

I want to create sparkle effect over an image as shown in the video Sparkle Effect the only way I could think of doing it animating each particle separately using core animation, but that would be inefficient as well as time consuming. Is there any other way I can do the same?



Solution 1:[1]

Here is a solution from Erica Susan's cook book. See this works for you.

You can add visual interest to your interfaces by using emitters in tandem with user touches. The following class demonstrates how to follow a touch over its lifetime, adding a little sparkle to wherever the user touches on-screen.

The class begins as soon as the user touches the screen, creating an emitter layer and a single emitter cell. The cell defines the particles — their color, their birth rate, their lifetime, velocity, and so forth.

As the user's touch progresses, this class updates the emitter's location, removing the emitter once the touch is removed from the screen. Although this example is written for single touch interaction, you can easily update the code to add an array of emitters (rather than a single instance) for multi-touch interaction.

Emitters are easily added to your projects and efficient to run. While too much animation is never a good design idea, a little sparkle used judiciously can add life and movement.

@interface SparkleTouchView : UIView {
    CAEmitterLayer *emitter;
}

@end

@implementation SparkleTouchView

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    float multiplier = 0.25f;

    CGPoint pt = [[touches anyObject] locationInView:self];

    //Create the emitter layer
    emitter = [CAEmitterLayer layer];
    emitter.emitterPosition = pt;
    emitter.emitterMode = kCAEmitterLayerOutline;
    emitter.emitterShape = kCAEmitterLayerCircle;
    emitter.renderMode = kCAEmitterLayerAdditive;
    emitter.emitterSize = CGSizeMake(100 * multiplier, 0);

    //Create the emitter cell
    CAEmitterCell* particle = [CAEmitterCell emitterCell];
    particle.emissionLongitude = M_PI;
    particle.birthRate = multiplier * 1000.0;
    particle.lifetime = multiplier;
    particle.lifetimeRange = multiplier * 0.35;
    particle.velocity = 180;
    particle.velocityRange = 130;
    particle.emissionRange = 1.1;
    particle.scaleSpeed = 1.0; // was 0.3
    particle.color = [[COOKBOOK_PURPLE_COLOR colorWithAlphaComponent:0.5f] CGColor];
    particle.contents = (__bridge id)([UIImage imageNamed:@"spark.png"].CGImage);
    particle.name = @"particle";

    emitter.emitterCells = [NSArray arrayWithObject:particle];
    [self.layer addSublayer:emitter];
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint pt = [[touches anyObject] locationInView:self];

    // Disable implicit animations
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    emitter.emitterPosition = pt;    
    [CATransaction commit];    
}

 - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [emitter removeFromSuperlayer];
    emitter = nil;
 }

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self touchesEnded:touches withEvent:event];
}

@end

Don't forget to create a png file named spark.png in order to create the animation.

Solution 2:[2]

/*Tested in swift 5.1*/    

Import UIKit

enum Images {
static let box = UIImage(named: "Box")!
static let triangle = UIImage(named: "Triangle")!
static let circle = UIImage(named: "Circle")!
static let swirl = UIImage(named: "Spiral")!
}

class ActivationRequiredViewController: UIViewController {

var emitter = CAEmitterLayer()

var colors:[UIColor] = [
    Colors.red,
    Colors.blue,
    Colors.green,
    Colors.yellow
]

var images:[UIImage] = [
    Images.box,
    Images.triangle,
    Images.circle,
    Images.swirl
]

var velocities:[Int] = [
    100,
    90,
    150,
    200
]

  override func viewDidLoad() {
    super.viewDidLoad()
   startSparkle()
}

func startSparkle() {
    emitter.emitterPosition = CGPoint(x: self.view.frame.size.width / 2, y:   -10)
    emitter.emitterShape = CAEmitterLayerEmitterShape.line
    emitter.emitterSize = CGSize(width: self.view.frame.size.width, height: 2.0)
    emitter.emitterCells = generateEmitterCells()
    self.view.layer.addSublayer(emitter)
}

private func generateEmitterCells() -> [CAEmitterCell] {
    var cells:[CAEmitterCell] = [CAEmitterCell]()
    for index in 0..<16 {
        
        let cell = CAEmitterCell()
        
        cell.birthRate = 4.0
        cell.lifetime = 14.0
        cell.lifetimeRange = 0
        cell.velocity = CGFloat(getRandomVelocity())
        cell.velocityRange = 0
        cell.emissionLongitude = CGFloat(Double.pi)
        cell.emissionRange = 0.5
        cell.spin = 3.5
        cell.spinRange = 0
        cell.color = getNextColor(i: index)
        cell.contents = getNextImage(i: index)
        cell.scaleRange = 0.25
        cell.scale = 0.1
        
        cells.append(cell)
    }
    return cells
}

private func getRandomVelocity() -> Int {
    return velocities[getRandomNumber()]
}

private func getRandomNumber() -> Int {
    return Int(arc4random_uniform(4))
}

private func getNextColor(i:Int) -> CGColor {
    if i <= 4 {
        return colors[0].cgColor
    } else if i <= 8 {
        return colors[1].cgColor
    } else if i <= 12 {
        return colors[2].cgColor
    } else {
        return colors[3].cgColor
    }
}

private func getNextImage(i:Int) -> CGImage {
    return images[i % 4].cgImage!
}

}

Solution 3:[3]

For anyone doing a Mac app, here's the same concept as @thevikasnayak , for an NSViewController

import Cocoa

enum Images {
    static let box = NSImage(named: "Box")!
    static let triangle = NSImage(named: "Triangle")!
    static let circle = NSImage(named: "Circle")!
    static let swirl = NSImage(named: "Spiral")!
}

class SparkleVC: NSViewController {
    var emitter = CAEmitterLayer()
    var colors:[NSColor] = [
        NSColor.blue.withAlphaComponent(0.1),
        NSColor.blue.withAlphaComponent(0.2),
        NSColor.blue.withAlphaComponent(0.3),
        NSColor.blue.withAlphaComponent(0.4)]
    var images:[NSImage] = [Images.box, Images.triangle, Images.circle, Images.swirl]

    override func viewDidAppear() {
        super.viewDidAppear()
        view.wantsLayer = true
        startSparkle()
    }
    
    func startSparkle() {
        emitter.emitterPosition = CGPoint(x: view.bounds.size.width / 2.0, y: view.bounds.size.height / 2.0)
        emitter.emitterShape = CAEmitterLayerEmitterShape.circle
        emitter.emitterSize = CGSize(width: view.bounds.size.width / 4.0, height: view.bounds.size.width / 4.0)
        emitter.emitterCells = generateEmitterCells()
        view.layer!.addSublayer(emitter)
    }

    private func generateEmitterCells() -> [CAEmitterCell] {
        var cells:[CAEmitterCell] = [CAEmitterCell]()
        for index in 0..<16 {
            let cell = CAEmitterCell()
            cell.birthRate = 200.0
            cell.lifetime = 0.01
            cell.lifetimeRange = 0.03
            cell.velocity = 5
            cell.velocityRange = 2
            cell.emissionLatitude = Double.random(in: 0 ..< Double.pi)
            cell.emissionLongitude = Double.random(in: 0 ..< Double.pi)
            cell.emissionRange = Double.pi
            cell.spin = 10
            cell.spinRange = 10
            cell.color = colors[index/4].cgColor
            cell.contents = nextImage(i: index)
            cell.scaleRange = 0.2
            cell.scale = 1
            cells.append(cell)
        }
        return cells
    }

    private func nextImage(i:Int) -> CGImage {
        return (images[i % 4]).cgImage(forProposedRect: nil, context: nil, hints: nil)!
    }
}

Solution 4:[4]

Please check this solution.

https://github.com/GabriellaQiong/CIS581-Project2-Image-Morphing

CIwarpKernel Kets you warp an image according to reference points. That is exactly what you want to do in order to have image morphing.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 thevikasnayak
Solution 3 Fattie
Solution 4 Samuel F.