I am working on a quiz application where , every question have different Time period .
I wants to implement an animation where circumference of circle should be decrease as time is over & at the end of time it will be lost . as shown in image here
Same behaviour I want in every question .
Please help me ,if nay one have any confusion please let me know.
Have a look at this control or this one
It is also worth finding out about Cocoapods, although the first control doesn't have a Pod yet.
To use these controls you can just add a UIView in IB and then set the custom class of the UIView to the control (such as kkprogresstimer).
testView is a UIView class which draws the Circle. Initializing this in a UIViewController class.
self.testView = [[TestView alloc] initWithFrame:CGRectMake(0.0, 0.0, 500.0, 700.0)];
self.testView.backgroundColor = [UIColor blueColor];
[self.view addSubview:self.testView];
timeLabel is the label which shows the remaining time.
self.timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(195.0, 195.0, 20.0, 12.0)];
[self.timeLabel setText:#"10"];
self.timeLabel.textColor = [UIColor redColor];
[self.view addSubview:self.timeLabel];
aTimer is a NSTimer variable which calls the myAnimate method every 2 seconds.
NSTimer *aTimer = [[NSTimer alloc] init];
aTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(myAnimate) userInfo:nil repeats:YES];
myAnimate method reduces the circumference of the circle and also the value of the timeLabel.
- (void)myAnimate {
[UIView animateWithDuration:5.0 animations:^{
if (self.testView.aFloat >= 36) {
int a = [self.timeLabel.text intValue];
self.timeLabel.text = [NSString stringWithFormat:#"%d", a -1];
self.testView.aFloat = self.testView.aFloat - 36;
[self.testView setNeedsDisplay];
}
} completion:nil];
}
UITestView draws the circle.
UITestView.h
#interface TestView : UIView
#property (nonatomic) CGFloat aFloat;
- (void)myAnimate;
#end
UITestView.m
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextAddArc(context, 200.0, 200.0, 75.0, 0, [self DegreesToRadians:_aFloat], 0);
CGContextStrokePath(context);
}
- (CGFloat)DegreesToRadians:(CGFloat)degrees {
return degrees * M_PI / 180;
}
Hope, this was of some assistance.
Related
I wrote an example about Wave Animation.The animation is ok,but I don't understand why the custom UIView needs to add "self.layer.masksToBounds = YES" to have the round Corner.
This is a custom UIView. I have rewritten its drawRect. If i don't set "masksToBounds" to YES, the round corner disappear.
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.frame = CGRectMake(10, 40, 300, 300);
self.layer.cornerRadius = 150;
self.backgroundColor = [UIColor greenColor];
self.layer.borderColor = [UIColor blueColor].CGColor;
self.layer.borderWidth = 2;
// self.layer.masksToBounds = YES; //if write this line,the round corner appear
self.x_move = 0;
self.y_move = 300;
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
CGContextSetLineWidth(context, 1);
CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
CGPathMoveToPoint(path, NULL, 0, 0);
for(float i=0; i<=300; i++){
float x=i;
float y = 5 * sin( 0.05 * x+ self.x_move) + self.y_move;
CGPathAddLineToPoint(path, nil, x, y);
}
CGPathAddLineToPoint(path, nil, 300, 0);
CGPathAddLineToPoint(path, nil, 0, 0);
CGContextAddPath(context, path);
CGContextFillPath(context);
CGContextDrawPath(context, kCGPathStroke);
CGPathRelease(path);
}
- (void)startAnimation {
if (self.waveTimer == nil) {
self.waveTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(refresh) userInfo:nil repeats:YES];
}
}
- (void)refresh {
self.x_move += 0.3;
self.y_move -= 0.2;
if(self.y_move - 100 < 0.00001){
[self.waveTimer invalidate];
}else{
[self setNeedsDisplay];
}
}
ViewController:
self.wave = [[waveAnimation alloc] init];
[self.wave startAnimation];
[self.view addSubview:self.wave];
This is a normal UIView. Its "masksToBunds" is NO, but its round corner shows normal. Compared with the examples above, why one should add, one does not need.
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 100, 100)];
view.backgroundColor = [UIColor greenColor];
view.layer.cornerRadius = 50;
view.layer.borderWidth = 2;
view.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview:view];
The reason for this is from your override of drawRect:(CGRect)frame.
You are attempting to set the corner radius of the layer that is not the element you assigned the fill color to. The reason setting masksToBounds achieves the desired rounded corner is because here you are telling the view to mask all of it's layers to the bounds from your frame.
In your second example with the UIView the corner radius appears as expected because you have not adjusted it's layers.
I suggest either adopting setting masksToBounds or redraw the view's bounds a different way if you need masksToBounds = NO. Since you have the "squiggle" sin curve and you want rounded corners, perhaps just create a generic rounded rect (one with the desired corner radius) then merge that with the path you have already created with the sin wave.
Merge multiple CGPaths together to make one path
That link may help you merge your rounded view with your custom view to achieve the desired end result.
Otherwise.. probably best bet to just set this to yes.
I've got a bit of a challenging thing I am trying to build.
Basically, I got this scenario here:
I am able to draw the dotted line thanks to this Stackoverflow answer:
Draw dotted (not dashed!) line, with IBDesignable in 2017
The dotted line drawing is done inside:
-(void)drawRect:(CGRect)rect
{
[self drawDottedLineFromStartingPoint:self.mainPhoto.center ToEndPoint:self.photo1.center];
[self drawDottedLineFromStartingPoint:self.mainPhoto.center ToEndPoint:self.photo2.center];
[self drawDottedLineFromStartingPoint:self.mainPhoto.center ToEndPoint:self.photo3.center];
[self drawDottedLineFromStartingPoint:self.mainPhoto.center ToEndPoint:self.photo4.center];
[self drawDottedLineFromStartingPoint:self.mainPhoto.center ToEndPoint:self.photo5.center];
}
-(void)drawDottedLineFromStartingPoint:(CGPoint)startPoint ToEndPoint:(CGPoint)endPoint
{
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:startPoint];
[path addLineToPoint:endPoint];
path.lineWidth = 4;
CGFloat dashes[] = {path.lineWidth * 0, path.lineWidth * 2};
[path setLineDash:dashes count:2 phase:0];
path.lineCapStyle = kCGLineCapRound;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(ctx, [ThemeManager mediumTextColor].CGColor);
[path stroke];
}
The problem I am facing is that each smaller circles animate in by falling down into place.
The way I am animating the smaller circle is by using something like:
CGAffineTransformMakeTranslation(0, 50);
When I do that, the dotted lines is drawn from the big circle to the final resting position of the smaller circle, the dotted lines doesn't "follow" the smaller circle as it's being animated and falling down.
So what you see is this:
Is there any easy solution to what I am trying to achieve ? I've tried thinking of using NSTimer and calculating the hypotenuse length, divide by a duration, but I didn't get very far :D
I made an app a while ago that did something similar to what you want, so I modified it do what you're trying to do. I have a class called NodeView, that's just a UIView subclass with one property, called line, which is a UIBezierPath (you could subclass UIImageView to do the same thing). I use a timer to move the nodes, and observe the node's center property so I can call drawRect to stroke the node's line. This version moves the nodes one by one. I set the controller's view to a subclass of UIView, and here's the code in that subclass,
#import "RDView.h"
#import "NodeView.h"
#interface RDView ()
#property (weak, nonatomic) IBOutlet UIView *bigView; // this is equivalent to your large image view from which the other image views drop
#property (strong,nonatomic) NSMutableArray *paths;
#end
#implementation RDView
-(void)didMoveToWindow {
self.bigView.layer.cornerRadius = self.bigView.frame.size.width/2.0;
self.paths = [NSMutableArray new];
self.nodes = [NSMutableArray new];
for (int i = 0; i<5; i++) {
NodeView *aNode = [NodeView new];
CGFloat hue = arc4random_uniform(1000)/1000.0;
aNode.backgroundColor = [UIColor colorWithHue:hue saturation:1 brightness:1 alpha:1.0];
aNode.frame = CGRectMake(0, 0, 40, 40);
[self.bigView layoutIfNeeded];
aNode.center = self.bigView.center;
[self addSubview:aNode];
[self.nodes addObject:aNode];
aNode.line = [UIBezierPath bezierPath];
CGFloat dashes[] = {0, aNode.line.lineWidth * 4};
[aNode.line setLineDash:dashes count:2 phase:0];
aNode.line.lineCapStyle = kCGLineCapRound;
[aNode.line moveToPoint:[self.bigView center]];
}
[self bringSubviewToFront:self.bigView];
for (NodeView *aNode in self.nodes) {
[aNode addObserver:self forKeyPath:#"center" options:NSKeyValueObservingOptionNew context:nil];
}
[self performSelector:#selector(dropNodes) withObject:nil afterDelay:1];
}
-(void)dropNodes {
static int i = 0;
[NSTimer scheduledTimerWithTimeInterval:.005 target:self selector:#selector(dropNode:) userInfo:#{#"nodeIndex":#(i)} repeats:YES];
i++;
}
-(void)dropNode:(NSTimer *) timer {
NSInteger i = [timer.userInfo[#"nodeIndex"] integerValue];
NodeView *node = self.nodes[i];
[node setCenter: CGPointMake(node.center.x + (i-2)*.25, node.center.y + 1)]; // spread the nodes out horizontally and move down
[node.line addLineToPoint:node.center];
if (node.center.y > 400) {
[timer invalidate];
if (i < self.nodes.count-1) {
[self dropNodes];
}
}
}
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"center"] ) {
[self setNeedsDisplay];
}
}
- (void)drawRect:(CGRect)rect {
for (NodeView *aNode in self.nodes) {
[aNode.line stroke];
}
}
You can find a link to my project here, http://jmp.sh/lIl5MXp
I want to thank rdelmar for enlightening me as well as this link informing me about a view's presentationLayer frame
ios observing change in frame of a UIView during animation
I didn't use KVO in this case but I did solved my problem using NSTimer and redrawing my screen.
Basically I after I start my animations for the circles falling down, I also schedule a NSTimer that triggers every 0.01 seconds and the callback method checks to see if the final circle photo has finished animating, if yes, then invalidate timer:
-(void)showIntroAnimations
{
self.hasBegunAnimating = YES;
// start animating circle photos falling down
[self setupObservers];
}
-(void)setupObservers
{
[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(redrawLines:) userInfo:nil repeats:YES];
}
-(void)redrawLines:(NSTimer *)timer
{
if([self.photo5.layer animationKeys].count > 0)
{
[self setNeedsDisplay];
}
else
{
[timer invalidate];
timer = nil;
}
}
I have created a simple audio player which plays a single audio. The views shows CAShapeLayer circular progress and also shows current time using CATextLayer. The figure below shows, the view:
Everything works fine until now, I can play, pause and the CAShapeLayer shows the progress. Now, I want to make it so that, when I touch the stroke (track) portion of the CAShapeLayer path, I would want to seek the player to that time. I tried few approaches but I could not detect touches on all parts of the stroke. It seems like the calculations I have done is not quite appropriate. I would be very happy if any body could help me with this.
Here is my complete code,
#interface ViewController ()
#property (nonatomic, weak) CAShapeLayer *progressLayer;
#property (nonatomic, weak) CAShapeLayer *trackLayer;
#property (nonatomic, weak) CATextLayer *textLayer;
#property (nonatomic, strong) AVAudioPlayer *audioPlayer;
#property (nonatomic, weak) NSTimer *audioPlayerTimer;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self prepareLayers];
[self prepareAudioPlayer];
[self prepareGestureRecognizers];
}
- (void)prepareLayers
{
CGFloat lineWidth = 40;
CGRect shapeRect = CGRectMake(0,
0,
CGRectGetWidth(self.view.bounds),
CGRectGetWidth(self.view.bounds));
CGRect actualRect = CGRectInset(shapeRect, lineWidth / 2.0, lineWidth / 2.0);
CGPoint center = CGPointMake(CGRectGetMidX(actualRect), CGRectGetMidY(actualRect));
CGFloat radius = CGRectGetWidth(actualRect) / 2.0;
UIBezierPath *track = [UIBezierPath bezierPathWithArcCenter:center
radius:radius
startAngle:0 endAngle:2 * M_PI
clockwise:true];
UIBezierPath *progressLayerPath = [UIBezierPath bezierPathWithArcCenter:center
radius:radius
startAngle:-M_PI_2
endAngle:2 * M_PI - M_PI_2
clockwise:true];
progressLayerPath.lineWidth = lineWidth;
CAShapeLayer *trackLayer = [CAShapeLayer layer];
trackLayer.contentsScale = [UIScreen mainScreen].scale;
trackLayer.shouldRasterize = YES;
trackLayer.rasterizationScale = [UIScreen mainScreen].scale;
trackLayer.bounds = actualRect;
trackLayer.strokeColor = [UIColor lightGrayColor].CGColor;
trackLayer.fillColor = [UIColor whiteColor].CGColor;
trackLayer.position = self.view.center;
trackLayer.lineWidth = lineWidth;
trackLayer.path = track.CGPath;
self.trackLayer = trackLayer;
CAShapeLayer *progressLayer = [CAShapeLayer layer];
progressLayer.contentsScale = [UIScreen mainScreen].scale;
progressLayer.shouldRasterize = YES;
progressLayer.rasterizationScale = [UIScreen mainScreen].scale;
progressLayer.masksToBounds = NO;
progressLayer.strokeEnd = 0;
progressLayer.bounds = actualRect;
progressLayer.fillColor = nil;
progressLayer.path = progressLayerPath.CGPath;
progressLayer.position = self.view.center;
progressLayer.lineWidth = lineWidth;
progressLayer.lineJoin = kCALineCapRound;
progressLayer.lineCap = kCALineCapRound;
progressLayer.strokeColor = [UIColor redColor].CGColor;
CATextLayer *textLayer = [CATextLayer layer];
textLayer.contentsScale = [UIScreen mainScreen].scale;
textLayer.shouldRasterize = YES;
textLayer.rasterizationScale = [UIScreen mainScreen].scale;
textLayer.font = (__bridge CTFontRef)[UIFont systemFontOfSize:30.0];
textLayer.position = self.view.center;
textLayer.bounds = CGRectMake(0, 0, 300, 100);
[self.view.layer addSublayer:trackLayer];
[self.view.layer addSublayer:progressLayer];
[self.view.layer addSublayer:textLayer];
self.trackLayer = trackLayer;
self.progressLayer = progressLayer;
self.textLayer = textLayer;
[self displayText:#"Play"];
}
- (void)prepareAudioPlayer
{
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"Song" withExtension:#"mp3"]
error:&error];
self.audioPlayer.volume = 0.2;
if (!self.audioPlayer) {
NSLog(#"Error occurred, could not create audio player");
return;
}
[self.audioPlayer prepareToPlay];
}
- (void)prepareGestureRecognizers
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(playerViewTapped:)];
[self.view addGestureRecognizer:tap];
}
- (void)playerViewTapped:(UITapGestureRecognizer *)tap
{
CGPoint tappedPoint = [tap locationInView:self.view];
if ([self.view.layer hitTest:tappedPoint] == self.progressLayer) {
CGPoint locationInProgressLayer = [self.view.layer convertPoint:tappedPoint toLayer:self.progressLayer];
NSLog(#"Progress view tapped %#", NSStringFromCGPoint(locationInProgressLayer));
// this is called sometimes but not always when I tap the stroke
} else if ([self.view.layer hitTest:tappedPoint] == self.textLayer) {
if ([self.audioPlayer isPlaying]) {
[self.audioPlayerTimer invalidate];
[self displayText:#"Play"];
[self.audioPlayer pause];
} else {
[self.audioPlayer play];
self.audioPlayerTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(increaseProgress:)
userInfo:nil
repeats:YES];
}
}
}
- (void)increaseProgress:(NSTimer *)timer
{
NSTimeInterval currentTime = self.audioPlayer.currentTime;
NSTimeInterval totalDuration = self.audioPlayer.duration;
float progress = currentTime / totalDuration;
self.progressLayer.strokeEnd = progress;
int minute = ((int)currentTime) / 60;
int second = (int)currentTime % 60;
NSString *progressString = [NSString stringWithFormat:#"%02d : %02d ", minute,second];
[self displayText:progressString];
}
- (void)displayText:(NSString *)text
{
UIColor *redColor = [UIColor redColor];
UIFont *font = [UIFont fontWithName:#"HelveticaNeue" size:70];
NSDictionary *attribtues = #{
NSForegroundColorAttributeName: redColor,
NSFontAttributeName: font,
};
NSAttributedString *progressAttrString = [[NSAttributedString alloc] initWithString:text
attributes:attribtues];
self.textLayer.alignmentMode = kCAAlignmentCenter;
self.textLayer.string = progressAttrString;
}
- (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
void(^animationBlock)(id<UIViewControllerTransitionCoordinatorContext>) =
^(id<UIViewControllerTransitionCoordinatorContext> context) {
CGRect rect = (CGRect){.origin = CGPointZero, .size = size};
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
self.progressLayer.position = center;
self.textLayer.position = center;
self.trackLayer.position = center;
};
[coordinator animateAlongsideTransitionInView:self.view
animation:animationBlock completion:nil];
}
#end
As far as I know the CALAyer hitTest method does a very primitive bounds check. If the point is inside the layer's bounds, it returns YES, otherwise it returns NO.
CAShapeLayer doesn't make any attempt to tell if the point intersects the shape layer's path.
UIBezierPath does have a hitTest method, but I'm pretty sure that detects touches in the interior of a closed path, and would not work with a thick line arc line the one you're using.
If you want to hit test using paths I think you're going to have to roll your own hitTest logic that builds a UIBezierPath that is a closed path defining the shape you are testing for (your thick arc line). Doing that for an animation that's in-flight might be too slow.
Another problem you'll face: You're interrogating a layer that has an in-flight animation. Even when you're simply animating the center property of a layer that doesn't work. Instead you have to interrogate the layer's presentationLayer, which is a layer that approximates the settings of an in-flight animation.
I think your best solution will be to take the starting and ending position of your arc, convert the start-to end value to starting and ending angles, use trig to convert your touch position to an angle and radius, and see if the touch position is in the range of the start-to-end touch and within the inner and outer radius of the indicator line. That would just require some basic trig.
Edit:
Hint: The trig function you want to use to convert x and y position to an angle is arc tangent. arc tangent takes an X and a Y value and gives back an angle. However, to use the arc tangent properly you need to implement a bunch of logic to figure out what quadrant of the circle your point is in.In C, the math library function you want is atan2(). The atan2() function takes care of everything for you. You'll convert your point so 0,0 is in the center, and atan2() will give you the angle along the circle. To calculate the distance from the center of the circle you use the distance formula, a² + b² = c².
I would like to implement a temporary alert into to a uitableviewcontroller to inform a user that their data has been saved.
I could do this with a uiAlertView - but for aesthetic reasons it would be preferable to implement something similar to the round cornered fade in/out alert view used in IOS7 for tasks such as showing volume control - as in this pic -
Is this a IOS7 class? I cant find any info on it (probably because I don't know what its called!), or would I need to extend the uiAlertView to replicate this functionality?
No, this is not a native iOS 7 subclass but there are plenty implementations of it in the wild. One example would be DTAlertView or CXAlertView or SDCAlertView. Check them out.
If you just want the volume-thingy type behavior, don't search too far. It's easily home-rolled with a full screen sized image view that's mostly transparent, and has in it's center a rounded-corner message rectangle, translucent if you like. Then build a convenience method to show/hide it with animation...
- (void)setAlertHidden:(BOOL)hidden animated:(BOOL)animated {
UIImageView *alertImageView = [self alertImageView];
BOOL currentlyHidden = alertImageView.alpha == 0.0;
if (currentlyHidden == hidden) return;
NSTimeInterval alpha = (hidden)? 0.0 : 1.0;
NSTimeInterval duration = (animated)? 0.3 : 0.0;
[UIView animateWithDuration:duration animations:^{
alertImageView.alpha = alpha;
} completion:^(BOOL finished) {
// if we showed the alert, hide it after 3 seconds
// you can make this duration a parameter
if (!hidden) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self setAlertHidden:YES animated:YES];
});
}
}];
}
All you need other than this is to build the image view lazily...
- (UIImageView *)alertImageView {
UIImageView *alertImageView = (UIImageView *)[self.view viewWithTag:999];
if (!alertImageView) {
alertImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
alertImageView.image = [UIImage imageNamed:#"fullscreen-volume-looking-thing.png"];
alertImageView.tag = 999;
[self.view addSubview:alertImageView];
}
return alertImageView;
}
Realize it's not exactly what you need, but this was pretty easy to paste together. It's the volume thing on a screen sized transparent background...
This is a quick implementation of a subview that will do what you want
#import "BellAlert.h"
#implementation BellAlert
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
UIImageView *bell = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Bell.png"]];
bell.frame = CGRectMake(0, 0, 50, 50);
bell.center = self.center;
[self addSubview:bell];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
CGContextMoveToPoint(context, 5, 0);
CGContextAddLineToPoint(context, 95, 0);
CGContextAddArcToPoint(context, 100, 0, 100, 5, 10);
CGContextAddLineToPoint(context, 100, 95);
CGContextAddArcToPoint(context, 100, 100, 95, 100, 10);
CGContextAddLineToPoint(context, 5, 100);
CGContextAddArcToPoint(context, 0, 100, 0, 95, 10);
CGContextAddLineToPoint(context, 0, 5);
CGContextAddArcToPoint(context, 0, 0, 5, 0, 10);
CGContextFillPath(context);
}
#end
If you want more complex functionality, you can implement public properties and a protocols
If you want to check it working look at it at GitHub... https://github.com/eharo2/BellAlert
for aesthetic reasons it would be preferable to implement something
similar to the round cornered fade in/out alert view used in IOS7
Rounding the corners of any view is incredibly easy:
someView.layer.cornerRadius = 5.0;
Making a view fade in and out is also trivial using Core Animation. For example, if you want to fade in someView, set its alpha property to 0 and then animate setting it to 1:
someView.alpha = 0.0;
[UIView animateWithDuration:1.0 animations:^{
someView.alpha = 1.0;
}];
With those tools at your disposal, you'll find it very easy to roll your own version of Apple's display.
I'm wanna create an effect like firework. I know that I can use for it CAEmitterCell. I tried to download few examples, but I still in progress with this feature in iOS 5.0
Anybody know good tutorial how to create firework effect using CAEmitterCell?
I need to create something like below:
All particles are going from the center (red circle) in direction to green circles. Red circle this is initial point that will have some CGPoint value.
I have found this solution:
it's how DWFParticleView.h file looks
#import <UIKit/UIKit.h>
#interface DWFParticleView : UIView
#property (nonatomic) CGFloat time;
-(void)configurateEmmiter;
-(void)setEmitterPositionFromTouch: (UITouch*)t;
-(void)setIsEmitting:(BOOL)isEmitting andPoint:(CGPoint)point;
#end
this is how looks DWFParticleView.m
#import "DWFParticleView.h"
#import <QuartzCore/QuartzCore.h>
#implementation DWFParticleView
{
CAEmitterLayer* fireEmitter; //1
}
-(void)configurateEmmiter
{
//set ref to the layer
fireEmitter = (CAEmitterLayer*)self.layer; //2
//configure the emitter layer
fireEmitter.emitterPosition = CGPointMake(50, 50);
fireEmitter.emitterSize = CGSizeMake(5, 5);
CAEmitterCell* fire = [CAEmitterCell emitterCell];
fire.birthRate = 0;
fire.lifetime = 2.0;
fire.lifetimeRange = 0.5;
//fire.color = [[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.6] CGColor];
fire.contents = (id)[[UIImage imageNamed:#"star_icon.png"] CGImage];
[fire setName:#"fire"];
fire.velocity = 80;
fire.velocityRange = 20;
fire.emissionRange = M_PI * 2.0f;
fire.scaleSpeed = 0.1;
fire.spin = 0.5;
//add the cell to the layer and we're done
fireEmitter.emitterCells = [NSArray arrayWithObject:fire];
fireEmitter.renderMode = kCAEmitterLayerAdditive;
}
+ (Class) layerClass {
return [CAEmitterLayer class];
}
-(void)setEmitterPositionFromTouch: (UITouch*)t
{
//change the emitter's position
fireEmitter.emitterPosition = [t locationInView:self];
}
-(void)setIsEmitting:(BOOL)isEmitting andPoint:(CGPoint)point
{
fireEmitter.emitterPosition = point;
//turn on/off the emitting of particles
[fireEmitter setValue:[NSNumber numberWithInt:isEmitting?50:0]
forKeyPath:#"emitterCells.fire.birthRate"];
[self performSelector:#selector(decayStep) withObject:nil afterDelay:self.time];
}
- (void)decayStep {
[fireEmitter setValue:[NSNumber numberWithInt:0]
forKeyPath:#"emitterCells.fire.birthRate"];
}
#end
this is method one tap on screen for example that shows our effect
- (void)tap {
DWFParticleView *fireView = [[DWFParticleView alloc] init];
fireView.time = 0.3;
[fireView setUserInteractionEnabled:NO];
[fireView configurateEmmiter];
[fireView setFrame:CGRectMake(0, 0, 0, 0)];
[fireView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:fireView];
}
the material I have found here: ray