I have set up an animation in the following way (self is an UIImageView, myImages an Array of UIImages):
self.animationImages = myImages;
self.animationDuration = 50;
self.animationRepeatCount = 0;
[self startAnimating];
During the animation I'd like to check the current image. I tried it the following way
if([self image]==[UIImage imageNamed:#"image1.png"]);
but this does not work. Is there a straight forward way for this? Can I keep track of which image is shown during the animation?
There is no official way to get the currently displayed image (index) from an animated UIImageView. Note: If the animationImages property contains a value other than nil, the contents of the image property is not used at all and will not contain usable data.
Still, you can measure the time that has passed since the animation started and evaluate the current frame/image index yourself.
Related
Hi everyone I'm french so scuse me for my english.My problem is the following: I have an image in the center of the screen called viewToRotate, then I have an image called flakeView that is created outside of the screen and then it is moving to the center, and every second a Timer does this(create a flakeView outside the screen and then move it to the center of the screen).
What I wanted to do was : if flakeView and viewToRotate collide reduce the alpha of viewToRotate to 0.5. But when flakeView appears on the screen the action of reducing the alpha is called without the collision of viewToRotate and flakeView, so they collide before they touches. I don't know why. How can I solve this please . Here is the code :
UIImageView* flakeView = [[[UIImageView alloc] initWithImage:flakeImage] autorelease];
// use the random() function to randomize up our flake attributes
int startY = round(random() % 320);
// set the flake start position
flakeView.center = CGPointMake(490, startY);
flakeView.alpha = 1;
// put the flake in our main view
[self.view addSubview:flakeView];
[UIView animateWithDuration:7
animations:^{
// set the postion where flake will move to
flakeView.center = viewToRotate.center;
}];
}
-(void)checkCollision{
if(CGRectIntersectsRect(flakeView.frame, viewToRotate.frame) == 1)
{
viewToRotate.alpha=0.5;
}
}
I would not suggest using a timer on viewDidLoad. I believe that you should set the timer at some other function. Even if you do not use viewDidLoad for anything else.
The other thing is the UIView animations. Even if you have a timer at every 60fps the attributes of the animated objects are not changed by the animation. So before you create the animation you set those properties once. And when you create the animation you set the same properties for the second time. And that's it. From now on while the animation is running if you do checks on the properties you will always get the second values.
To have a working code one option is to create the UIView animations (and perform the property checks) for every step at a certain time interval. Or use OpenGL.
Before getting too deep into this issue, please also make sure that your viewToRotate.frame is actually sized the way you expect it (see my comment).
Once you are certain about those attributes, you might want to check the collision on the current presentationLayer of your animated objects and not on their original state.
UIView.layer.presentationLayer
Returns a copy of
the layer containing all properties as
they were at the start of the current
transaction, with any active
animations applied.
So you might adapt your collision detection like this:
-(void)checkCollision
{
if(CGRectIntersectsRect(flakeView.layer.presentationLayer.frame, viewToRotate.layer.presentationLayer.frame) == 1)
{
viewToRotate.alpha=0.5;
}
}
Also consider using the CoreAnimation Layer method hitTest: instead of your handmade collision detection.
hitTest: Returns the farthest
descendant of the receiver in the
layer hierarchy (including itself)
that contains a specified point.
These are the following things you would want to check.
Dont init with image, use init with frame and then do
flakeView.image = ----; Because your image could be wide enough
initially , and hence colliding from the time you initialize.
Try alternatives to .center, like .frame.size.x , because I have had
problems with .center as well
You could probably NSLog the bounds of both ur imageviews before and
after reducing alpha
I want to add around 80 imageview on my view and then later on want to change their images very frequently(multiple times per second, working on an audio meter). I have added images using following code:
-(void)drawAudioMeter {
UIImageView *imgvw = nil;
int x = 1;
for(int i = 0; i<80; i++) {
imgvw = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"line_dull.png"]];
imgvw.tag = i+100;
imgvw.frame = CGRectMake(x, 400, 3, 30);
x = x + 4;
[self.view addSubview:imgvw];
[imgvw release];
}
}
Now how will I change the images in the imageviews as I am not having any name for the imageviews. Using a for loop every second on all the images does not look as feasible option to me. Can some one point me out how should I do it?
You can use viewWithTag to get a specific image by its tag
UIIMageView *image = [UIView viewWithTag:1];
viewWithTag: Returns the view whose
tag property contains the specified
integer value.
(UIView *)viewWithTag:(NSInteger)tag Parameters tag The tag value to search
for. Return Value The view in the
receiver’s hierarchy whose tag
property matches the value in the tag
parameter.
Discussion This method searches the
current view and all of its subviews
for the specified view.
Availability Available in iOS 2.0 and
later. See Also #property tag
Related Sample Code GenericKeychain
SeismicXML Declared In UIView.h
taken from: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html
Create array of UIImageView's in your .h file
UIImageView* imgvw[80];
Create the imgvw's in a forloop in viewDidLoad.
And remove creating and releasing of image views in your for loop. And so, in your drawAudioMeter, you can just get the object of your image view in the for loop and change the images accordingly.
I think it's not good idea to draw audio meter via 80 UIImage's ... Maybe you should look at SpeakHere example from Apple how they do this. Open Xcode, open help (option-cmd-?) and search for SpeakHere. It's an example which does record / playback audio with audio meter.
I have a few buttons I would like to animate.
I have looked at and tried the animateWithDuration method but that seems to be for Views and I couldnt get my implementation to work.
Can this method work for animating buttons too? if not how could it be done?
EDIT
I have the following code
-(void) animate:(UIButton*) b withMonster: (int) monster withState: (int) state andLastState:(int) last_state {
if (state < last_state) {
float duration = 1.0 / 10;
__block int stateTemp = state;
[b animateWithDuration: duration
animations: ^{ [UIImage imageNamed:[NSString stringWithFormat:#"m%d.a000%d.png", monster, state]]; }
completion: ^{ [self animate: A1 withMonster: monster withState: stateTemp++ andLastState: last_state];; }];
}
and I call it like so
[self animate: A1 withMonster: monsterDecider withState: 1 andLastState: 5];
When this code executes the app crashes.
Is it correct to call is with self in both calls(self being ViewController).
Thanks
You can animate buttons, yes. In the animations block you need to change some of the button parameters like this:
[UIView animateWithDuration:animTime
animations:^{button.frame = newFrame;}];
Looking at your code you probably want to set the button.imageView.image property to a new image (your code currently loads a new image but doesn't set it onto the button).
However, UIImageView objects actually support changing between multiple images without needing to use the UIView animateWithduration:... methods.
You probably want to set the following properties:
button.imageView.animationImages
button.imageView.animationDuration
button.imageView.animationRepeatCount
Then call
[button.imageView startAnimating];
and the UIImageView will do all the animation for you.
See the docs on UIImageView:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIImageView_Class/Reference/Reference.html
I'm developing an app that would display images and change them according to the user's action. I've created a subclass of UIView to contain an image, an index number and an array of image names. The code is like this:
#interface CustomPic : UIView {
UIImageView *pic;
NSInteger index;
NSMutableArray *picNames; //<-- an array of NSString
}
And in the implementation part, it has a method to change the image using a dissolve effect.
- (void)nextPic {
index++;
if (index >= [picNames count]) {
index = 0;
}
UIImageView *temp = pic;
pic.image = [UIImage imageNamed:[picNames objectAtIndex:index]];
temp.alpha = 0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.25];
pic.alpha = 0;
temp.alpha = 1;
[UIView commitAnimations];
}
In the viewController, there are several CustomPic which would change the images depends on users' choice. The images would change as expected with the fade in/out effect, but the animation performance is really bad. I've tested it on an iPhone 3G, the Instruments shows that the animation is only 2-3FPS! I tried many methods to simplify and modify the codes but with no hope. Is there something wrong in my code or in my concept? Thanks for any help.
P.S. all the images are 320*480 PNGs with a max size of 15KB.
In that code snippet you are only using one UIImageView:
UIImageView *temp = pic;
So this line does nothing:
pic.alpha = 0;
To fade one image in and another image out, you need two instances of UIImageView.
To speed things up, you might want to load the next image ahead of time. Set a delegate for the animation, and when it completes load the image that will be displayed in the next call of nextPic.
Edit:
If the images are not transparent, try setting the pic.opaque = YES; so the view can ignore underlying views. If that is not an option, try having as few views as possible between the fading view and a full screen opaque view. At each step of the fade, the view must be composited with every underlying view until an opaque view is found.
If you have many transparent views under the fade, consider making a temporary composite of them all, the equivalent of flatten layers in photoshop, and placing the composite as an image in a full screen opaque view before starting the fade. It may delay starting the fade a moment, but the fade itself should be smoother.
Are you running iPhone OS 4 beta? I find the beta OS much slower on the older generation devices like iphone 3g
Try change
[UIView setAnimationDuration:0.25];
to
[UIView setAnimationDuration:0.025];
and see if that's something you are looking for...
With an animation duration of .25 of a second, you can be guaranteed to get < 4 FPS. What FPS are you targeting?
I am trying to rotate my object like shakes dice.
please suggest simplest way to implement it in my iphone application.
Any kind of sample code or documentation.
http://www.amazon.com/OpenGL-SuperBible-Comprehensive-Tutorial-Reference/dp/0321498828
If you want to do this without using OpenGL you can use a UIImageView and the set a series of animation images. By creating a series of images you can create a "rolling dice" effect. Here is an example of how to do this:
// create a UIImageView
UIImageView *rollDiceImageMainTemp = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"rollDiceAnimationImage1.png"]];
// position and size the UIImageView
rollDiceImageMainTemp.frame = CGRectMake(0, 0, 100, 100);
// create an array of images that will represent your animation (in this case the array contains 2 images but you will want more)
NSArray *savingHighScoreAnimationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"rollDiceAnimationImage1.png"],
[UIImage imageNamed:#"rollDiceAnimationImage2.png"],
nil];
// set the new UIImageView to a property in your view controller
self.viewController.rollDiceImage = rollDiceImageMainTemp;
// release the UIImageView that you created with alloc and init to avoid memory leak
[rollDiceImageMainTemp release];
// set the animation images and duration, and repeat count on your UIImageView
[self.viewController.rollDiceImageMain setAnimationImages:savingHighScoreAnimationImages];
[self.viewController.rollDiceImageMain setAnimationDuration:2.0];
[self.viewController.rollDiceImageMain.animationRepeatCount:3];
// start the animation
[self.viewController.rollDiceImageMain startAnimating];
// show the new UIImageView
[self.viewController.view addSubview:self.rollDiceImageMain];
You can modify the creation and setup including the size, position, number of images, the duration, repeat count, etc as needed. I've used this feature of UIImageView to create simple animation effects and it works great!
Please let me know if you try this and if it works for your needs. Also, post any follow up questions.
Bart
nice your example, but do you think it's possible to rotate / control the rotation with touch gesture ?