闪光效果 iOS

6
我想在图片上创建类似于Sparkle Effect视频中的闪烁效果,但我唯一能想到的方法是使用核心动画单独对每个粒子进行动画处理,但这样会很耗费时间且效率低下。是否有其他方法可以实现相同的效果?

单独使用核心动画对每个粒子进行动画处理会效率低下且耗时。- 那你有进行基准测试吗? - user529758
4个回答

13

这里是Erica Susan烹饪书中的一个解决方案。看看它是否适用于你。

通过与用户触摸配合使用发射器,您可以为界面增加视觉趣味性。以下类演示了如何跟踪触摸的生命周期,在用户屏幕上触摸的任何位置添加一些闪烁。

当用户触摸屏幕时,该类立即开始创建一个发射器层和一个单个的发射器单元。单元定义了粒子-它们的颜色、出生率、寿命、速度等等。

随着用户的触摸进展,该类更新发射器的位置,并在从屏幕中删除触摸后删除发射器。虽然此示例是针对单触摸交互编写的,但您可以轻松地更新代码以添加一组发射器(而不是单个实例),以进行多点触摸交互。

发射器很容易添加到您的项目中,并且运行效率高。虽然过多的动画不是好的设计理念,但适度使用一点闪烁可以增加生动感和动态感。

@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

别忘了创建一个名为spark.png的png文件,以便创建动画。


1
她在工作中使用预设颜色,以便在单个类中轻松访问它。您可以使用自己选择的CG颜色。我会选择[uicolor colorwithred:来控制颜色和透明度,或者[bicolor colorwithcgcolor并为其设置特定的CG颜色。这部分由您决定。 - Adrian P
稍作更正:应该是一个名为spark.png的文件,不是吗?或者我读错代码了吗? - David Doyle
spark.png文件有多少像素?它是什么?一个微小的,白色或银色的单个火花吗? - Doug Null
@DouglasK.Bell,我会使用一个小图像。大约是10 X 10或者其他你想要的大小。形状由你决定,大小也是。越小效果越好。我用一个10像素的图像构建了上面的代码,看起来很好,但这真的取决于你。图像可以是简单的星形或任何其他形状。 - Adrian P
只是为了表扬功劳所在,这是Erica Sadun - 就像“iOS 5开发者手册:iOS核心概念和必备配方...作者Erica Sadun”。 - Joe
显示剩余4条评论

0

对于任何正在开发Mac应用的人,这里有一个与@thevikasnayak相同概念的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)!
    }
}

0
/*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!
}

}

不需要额外的库或pod来实现。苹果在UIKit中有自己的*CAEmitterLayer()*,使其成为可能。 - thevikasnayak

-2

这并没有提供问题的答案。如果您想对作者进行批评或请求澄清,请在他们的帖子下留言。 - Bruce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接