CAEmitter any way to insert self-animated particles? - ios

I have a CAEmitterCell :
CAEmitterCell * spriteCell = [CAEmitterCell emitterCell];
spriteCell.contents = (id) [[UIImage imageNamed:#"emitterSprite.png"] CGImage];
I would like the sprite to be an animated png sequence (or so) instead of a single image.
The only technique I know makes use of an UIImageView :
NSMutableArray *animatedImagesArray = [NSMutableArray new];
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(...)];
for (int i = 1; i <= 10; i++)
{[animatedImagesArray addObject:[UIImage imageNamed:[NSString stringWithFormat:#"sequenceNo-%d%#", i, #".png"]]];}
imageView.animationImages = animatedImagesArray;
[view addSubview:imageView];
CAEmitterCell.contents doesn't seem to accept UIImageView. Is there a way to achieve this ?

For reasons of performance in the operating system what you are trying to do is not possible. If you have simple transformations like rotation, scale, colour tint you can edit those values in the properties of your the CAEmitterCell. If you require a more complex animation you will need to use a custom emitter that can handle UIImageViews. But be mindful of the performance implications.

Related

Faster way to take snapshots ios

I have a UICollectionView. I want to generate two snapshots for each objects.
Sample Code:
for (int index = 0; index < 2; index++) {
UIView *dummyView = [[UIView alloc] init];
dummyView.frame = some frame....,
dummyView.backgroundColor = [UIColor yellowColor];
UIGraphicsBeginImageContextWithOptions(dummyView.bounds.size, NO, [UIScreen mainScreen].scale);
[dummyView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imgData= UIImageJPEGRepresentation(outputImage, 1.00f);
//Write file.
}
I have written the code in cellForItemAtIndexPath. If there is no image in the path, it will create automatically. So when I launch the application for the first time, the UI is not responsive since there are many snapshots are getting created. This slow down the user interaction. Is there any work around for this?
Use drawViewHierarchyInRect instead of drawInContext as it's much faster
See the iOS 7 example here: https://coderwall.com/p/56wcfq/fast-snapshot-any-views-on-ios-7

NSMutableArray creates issue for images

I have an array with dictionaries in it. Each dictionary contains UIImage & String values.
But when I try to delete object using
[arr removeObjectAtIndex:button.tag];
then it just decreases the count but image (Object) is not deleted.
So, my Images are overlapping when try to delete.
It also creates problem when I try to add objects in the array
[arr insertObject:dict atIndex:0];
so, I used
[_postObj.arr_images addObject:dict]; instead of insertObject
Help me to solve this
Objects use reference counting and both NSMutableArray and UIImageView will retain the UIImage object.
This means that removing it from the array will not automatically remove it from the UIImageView and you must remove it from both explicitly:
[arr removeObjectAtIndex:button.tag];
_imageView.image = nil;
Problem is in your frame setting of UIImageView. Please try using below code (not tested by myself) and see if this fixes the issue for you. Basically, I am adjusting X position of images based on previous image's width.
CGFloat imageXM = 5.0;
CGFloat imageXPos = 0;
for (UIImage *image in arr_images) {
CGRect imageFrame = CGRectMake(imageXPos + imageXM, 0.0, image.size.width, image.size.height);
imageXPos = imageXPos + image.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageFrame];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = image;
[scl addSubview:imageView];
}
As in your code
[picker dismissViewControllerAnimated:YES completion:^{
[arr_images insertObject:chosenImage atIndex:0];
[self scrollImages_Setup2];
}];
[arr_images insertObject:chosenImage atIndex:0]; that means you need only one image to display on scroll view. Then why you take a loop:
-(void)scrollImages_Setup2
{
for (int k=0; k<arr_images.count; k++) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((CGRectGetWidth(scl.frame) * k) + CGRectGetWidth(scl.frame), 0, CGRectGetWidth(scl.frame), CGRectGetHeight(scl.frame))];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image=[arr_images objectAtIndex:k] ;
[scl addSubview:imageView];
}
scl.contentSize = CGSizeMake((CGRectGetWidth(scl.frame) * arr_images.count)+CGRectGetWidth(scl.frame), CGRectGetHeight(scl.frame));
}
You just right the code only for display the Image. you don't need to scroll view for displaying only one image. I think you are not clear what you want.
Your problem regarding the overwriting the images because of loop. so remove the loop, when you display a single image. Please remove the scrollview contentSize, because image_array will increase, when you add the multiple images in array and size width will be large. so remove arr_images.count as well.

Multiple views with shadow and rotation becomes very slow

I'm trying to make multiple stacks of uiview's. Each of those UIView's with a shadow, slight rotation and scale. As a test I'm making 10 stack's of 10 views. Drawing all this is very slow.. Is there a good way to optimise this? I tried making the shadow and background from a image but that was ugly and equally as slow. I put these stacks in a UIScrollView
for (int k = 0; k < 9; k++) {
for (int i = 0; i < 9; i++) {
UIView *stack = [[UIView alloc] initWithFrame:CGRectMake((i * 106), (k * 106), 110, 110)];
for (int i = 0; i < 10; i++) {
CardView *cardView = [[CardView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
//cardView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"card_background.png"]];
cardView.layer.shadowOffset = CGSizeMake(0, 0);
cardView.layer.shadowOpacity = 0.3f;
cardView.layer.shadowPath = [UIBezierPath bezierPathWithRect:(CGRect){CGPointZero, cardView.layer.bounds.size}].CGPath; // Set shadow path, without this the performance is *really* bad
cardView.transform = CGAffineTransformMakeRotation(((arc4random() % 20) - 10.0f) / 100.0f);
cardView.transform = CGAffineTransformScale(cardView.transform, 0.35, 0.35);
cardView.layer.shouldRasterize = YES;
cardView.layer.rasterizationScale = 0.5;
cardView.center = CGPointMake(55, 55);
[stack addSubview:cardView];
}
[_backgroundView addSubview:stack];
}
}
Edit 1; Tried some stuff, disabling rasterzation isn't helping much, disabling the shadow doesn't help much either, rotation and scaling are recourse intensive with this much uiview's too. Would async drawing (one stack at the time) be an option?
Edit 2; Guess making 100 UIView's is just slow anyway. I'll report back if I've found a better (I guess async or something like that) solution
Are you using these images in some sort of animation? If not you can try turning off rasterizing to increase performance.
cardView.layer.shouldRasterize = NO;
Shadows are very computationally intensive. If shouldRasterize doesn't do it, make a UIImage for the shadow, and if your views can change size, load the image with resizableImageWithCapInsets.

Core Plot Not Displaying Axis Labels With Images When collapsesLayers is YES

I am drawing icons at custom tick locations in an xy graph with a scatter plot using Core Plot 1.0 on iOS 5. I've been having performance issues on the iPad 3 with allowing user interaction and scrolling the graph horizontally. I started looking into using the collapsesLayers property of CPTGraphHostingView as a potential solution. Enabling it works quite well for me except for one particular issue that I have not yet been able to solve. My custom axis labels set up to render images will not display. I'm wondering if anyone has any thoughts about what might be the cause. As near as I can tell the axis labels are still being positioned properly at the correct custom tick locations. The only difference in my external code is swapping collapsesLayers from NO to YES.
Here is how I am constructing the axis labels:
+ (CPTAxisLabel *)buildIconAxisLabelAtLocation:(CGFloat)location withImageNamed:(NSString *)imageName
{
CPTLayer *imageLayer = [[CPTLayer alloc] initWithFrame:CGRectMake(0, 0, 16, 16)];
UIImage *image = [UIImage imageNamed:imageName];
CALayer *imageSubLayer = [[CALayer alloc] init];
imageSubLayer.frame = imageLayer.frame;
imageSubLayer.contents = (id)image.CGImage;
[imageLayer addSublayer:imageSubLayer];
CPTAxisLabel *iconLabel = [[CPTAxisLabel alloc] initWithContentLayer:imageLayer];
iconLabel.offset = 8;
iconLabel.tickLocation = CPTDecimalFromCGFloat(location);
iconLabel.rotation = M_PI;
return iconLabel;
}
Any help is appreciated.
Every layer in a Core Plot graph should be a CPTLayer or a subclass. This has many implications for layout and drawing.
Core Plot doesn't render the layer contents. Use a CPTBorderedLayer with an image fill instead.
I would try something like this:
UIImage *image = [UIImage imageNamed:imageName];
CPTImage *background = [CPTImage imageWithCGImage:image.CGImage];
CPTBorderedLayer *imageLayer = [[CPTBorderedLayer alloc] initWithFrame:CGRectMake(0, 0, 16, 16)];
imageLayer.fill = [CPTFill fillWithImage:background];

Creating a custom progress bar with images

Pretty much what I am trying to do, is create the following image:
So this is a progress bar, which will show how many votes the client get in that option. How can I do that? I was wondering if I can use a mask (as I would in flex), but all the masking implementations that I found on the web are doing masks for UIImages, and not for UIImageView. I cannot do the mask in the UIImage, because the two images have the same dimensions. I have to use the X and Y of the images to crop them?! So, any suggestions?
Here are the two images that I have to create that progress bar:
Cheers.
you want to get rid of all of the same bit in the middle of each image.
then do something like:
- (void)viewDidLoad
{
[super viewDidLoad];
[self addProgressBarInFrame:CGRectMake(20.f, 20.f, 280.f, 50.f) withProgress:.9f];
[self addProgressBarInFrame:CGRectMake(20.f, 100.f, 200.f, 25.f) withProgress:.1f];
}
-(void)addProgressBarInFrame:(CGRect)frame withProgress:(CGFloat)progress
{
float widthOfJaggedBit = 4.0f;
UIImage * imageA= [[UIImage imageNamed:#"imageA"] stretchableImageWithLeftCapWidth:widthOfJaggedBit topCapHeight:0.0f];
UIImage * imageB= [[UIImage imageNamed:#"imageB"] stretchableImageWithLeftCapWidth:widthOfJaggedBit topCapHeight:0.0f];
UIView * progressBar = [[UIView alloc] initWithFrame:frame];
progressBar.backgroundColor = [UIColor whiteColor];
UIImageView * imageViewA = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, frame.size.width*progress, frame.size.height)];
UIImageView * imageViewB = [[UIImageView alloc] initWithFrame:CGRectMake(frame.size.width*progress, 0.f, frame.size.width - (frame.size.width*progress), frame.size.height)];
imageViewA.image = imageA;
imageViewB.image = imageB;
// imageViewA.contentStretch = CGRectMake(widthOfJaggedBit, 0, imageA.size.width - 2*widthOfJaggedBit, imageA.size.height) ;
// imageViewB.contentStretch = CGRectMake(widthOfJaggedBit, 0, imageB.size.width - 2*widthOfJaggedBit, imageB.size.height) ;
[self.view addSubview:progressBar];
[progressBar addSubview:imageViewA];
[progressBar addSubview:imageViewB];
}
Grady Player's answer is great. Just a small note, for anyone that uses this. I tried to update the frames of the two UIImageView's to update the "progress". I tried to force an update with "setNeedsDisplay", but to no avail. (sizeToFit caused problems too).
Anyway, the only way I figured out how to update the progress of an existing progress bar was to call "setFrame:CGRectMake" with my new dimensions.

Resources