I want to smothly animate an image in an UIImageView to turn into the next one within one second like UIModalTransitionStyleCrossDissolve does.
Currently, I've got an UIImageView * called "imageView" and a function which is called "imageForState" which returns me a UIImage * for the correct image.
So what I want to do is to animate the image A smoothly into image B if there is one.
Currently, my function is like that:
- (UIImage *) imageForState{
NSLog(#"state: %d", [save state]);
switch ([save state]) {
case 0:
case 1:
return [UIImage imageNamed:#"Sakuya_Debug.PNG"];
case 2:
return [UIImage imageNamed:#"Sakuya_2_Debug.PNG"];
default:
return NULL;
//Never called
}
}
-(void) tap{
[imageView setAnimationImages:[NSArray arrayWithObjects:[imageView image], [self imageForState], nil]];
imageView.animationDuration = 2.0;
[imageView startAnimating];
save.state++;
}
My problem is, that 1.) the animation goes on forever (when I set imageView.animationRepeatCount to 1, I end up at the first image again) and b.) the animation is not smooth; just like I would have used "setImage";
What am I doing wrong?
I suggest doing it with two imageViews and an animation block. In the following example I assume two square images with a siza of 100px. If you add the two imageViews as subviews make sure that imageB is added after imageA so it covers it.
Init the imageViews:
UIImageView *imageA = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Sakuya_Debug.PNG"]];
UIImageView *imageB = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Sakuya_2_Debug.PNG"]];
// hide the second image
imageB.alpha = 0.0;
// put the image with the same size at same position
imageA.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
imageB.frame = imageA.frame;
Blend method:
- (void)crossDissolveImageAtoB
{
[UIView animateWithDuration:1.0
animations:^{
imageB.alpha = 1.0;
}
completion:^(BOOL finished){
// do something after the animation finished,
// maybe releasing imageA if it's not used anymore...
}];
}
Related
I'm trying to use a custom overlay on the UIImagePickerController and also be able to move and scale the resulting image. The problem is when I set showsCameraControls=YES, the overlay won't show but I can use the the move and scale functionality. However, when showsCameraControls=NO, the overlay appears, but when I take the picture, I don't even get the option to crop the image. The actual view loaded from the xib is just a UIToolbar with two buttons, one of which takes the picture
I have a controller (OverlayViewController) which loads the overlay from a xib file as it's view. This controller also has a UIImagePickerController so it sets the overlay of the UIImagePickerController to the view of the OverlayController. This first method is called in a different controller to set it all up and display it. In summary, I need to be able see the overlayView and use it's button to take the picture, which I can then move and scale
-(void) openCameraForImage
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
self.overlayViewController =
[[OverlayViewController alloc] initWithNibName:#"OverlayViewController" bundle:nil];
// as a delegate we will be notified when pictures are taken and when to dismiss the image picker
self.overlayViewController.delegate = self;
[self.overlayViewController setupImagePicker:UIImagePickerControllerSourceTypeCamera];
[self presentModalViewController:self.overlayViewController.imagePickerController animated:YES];
}
else {
[Common ShowAlert:#"Alert" andMessage:#"There is no camera on this device"];
}
}
This method is in OverlayViewController and does the work of setting up the Overlay.
- (void)setupImagePicker:(UIImagePickerControllerSourceType)sourceType
{
self.imagePickerController.sourceType = sourceType;
[self.imagePickerController setAllowsEditing:YES];
if (sourceType == UIImagePickerControllerSourceTypeCamera)
{
// user wants to use the camera interface
//
self.imagePickerController.showsCameraControls = NO; //This line allows overlay to show but move and scale doesn't work
self.imagePickerController.allowsEditing = YES;
//[self.view setUserInteractionEnabled:NO];
if ([[self.imagePickerController.cameraOverlayView subviews] count] == 0)
{
// setup our custom overlay view for the camera
//
// ensure that our custom view's frame fits within the parent frame
CGRect overlayViewFrame = self.imagePickerController.cameraOverlayView.frame;
CGRect newFrame = CGRectMake(0.0,
CGRectGetHeight(overlayViewFrame) -
self.view.frame.size.height - 10.0,
CGRectGetWidth(overlayViewFrame),
self.view.frame.size.height + 10.0);
self.view.frame = newFrame;
self.imagePickerController.cameraOverlayView = self.view;
}
}
}
This method in OverlayViewConroller takes the picture
- (IBAction)takePhoto:(id)sender
{
[self.imagePickerController takePicture];
}
I think you can put your image picker code in openCameraForImage
In your OverlayViewController, just use it to purely show the Overlay for your camera.
#implementation RiskCameraOverlayViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view setBackgroundColor:[UIColor blackColor]];
opUpImage = [UIImage imageNamed:#"camera_overlay_op_up"];
opDownImage = [UIImage imageNamed:#"camera_overlay_op_down"];
opUpFrameBegin = CGRectMake(0, -50, 320, 358);
opUpImageView = [[UIImageView alloc] initWithFrame:opUpFrameBegin];
[opUpImageView setImage:opUpImage];
opDownFrameBegin = CGRectMake(0, 265, 320, 314);
opDownImageView = [[UIImageView alloc] initWithFrame:opDownFrameBegin];
[opDownImageView setImage:opDownImage];
[self.view addSubview:opUpImageView];
[self.view addSubview:opDownImageView];
}
You might reach an issue where "Use photo" or "Retake" is not working, do a
[self.view removeFromSuperview];
I am trying to find the current position of an iPhone ImageView that is animating across the screen.
I create and animate the imageView like so
-(IBAction)button:(UIButton *)sender{
UIImageView *myImageView =[[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"ball.png"]];
myImageView.frame = CGRectMake(0, self.view.frame.size.height/2, 40, 40);
[self.view addSubview:myImageView];
[myArray addObject:myImageView];
[UIView animateWithDuration:.5
delay:0
options:(UIViewAnimationOptionAllowUserInteraction) // | something here?)
animations:^{
myImageView.frame = CGRectOffset(myImageView.frame, 500, 0);
}
completion:^(BOOL finished){
[myArray removeObject:myImageView];
[myImageView removeFromSuperview];
[myImageView release];
}
];
}
then to detect the current CGPoint of the imageView I call this method every 60th of a second
-(void)findPoint{
for (UIImageView *projectile in bullets) {
label.text = [NSString stringWithFormat:#"%f", projectile.center.x];
label2.text = [NSString stringWithFormat:#"%f", projectile.center.y];
}
}
However this only gives me the point where the animation ends, I want to get the current CGPoint of the image that is animating across the screen. Is there an option that I need to apply other than UIViewAnimationOptionAllowUserInteraction to do this? If not, how do I get the current position of an animating imageView?
You can use the presentationLayer - a property of the CALayer that "provides a close approximation to the version of the layer that is currently being displayed". Just use it like this:
CGRect projectileFrame = [[projectile.layer presentationLayer] frame];
Swift 5:
Get temporary position and size (CGRect) during the animation with:
let currentFrame = projectileFrame.layer.presentation()!.frame
I have a method with an image "imageView":
- (void)createNewImageView {
// Get the view's frame to make it easier later on
UIImage *image = [UIImage imageNamed:#"abouffer_03.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// Add it at a random point
[imageView setCenter:[self randomPointSquare]];
[[self view] addSubview:imageView];
// Animate it into place
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:8.0f];
[imageView setCenter:CGPointMake(240, 160)];
[UIView commitAnimations];
[imageView release];
}
and another image "viewToRotate" (IBOuutlet defined in .h and interface builder)
And I want to check the collision with this method :
- (void)myRunloop
{
// check collision
if( CGRectIntersectsRect(imageView.frame, viewToRotate.frame) )
{
viewToRotate.alpha=0.2;
}
}
But xcode always give me the error :"imageView undeclared" and I don't know how to solve this . I don't wanna define it again in this method.
I just'd been through a similar problem actually when you set the frame of the imageView on line
[imageView setCenter:CGPointMake(240, 160)];
the imageView gets settled at that point in the memory, It's just that due to being in animation block it's showing you the transition that imageView is being moved towards the destination but in actual the view's coordinates are assigned with the destination location, you can confirm it by logging coordinates right after the line of code. If you really need to do this the similar way, you can use the timer instead of the animation block and animate yourself. But I circumvent this problem by using the animationDelegate. Just set animation delegate to self and define animationDidStopSelector and you're up. You're animationDidstopSelector will get fired when the animation's ended and hence the object reached it's final destination or you can say there's a collision (on UI). Hope that helps
Here's a code sample:
- (void)createNewImageView {
// Get the view's frame to make it easier later on
UIImage *image = [UIImage imageNamed:#"abouffer_03.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// Add it at a random point
[imageView setCenter:[self randomPointSquare]];
[[self view] addSubview:imageView];
// Animate it into place
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:)];
[UIView setAnimationDuration:8.0f];
[imageView setCenter:CGPointMake(240, 160)];
[UIView commitAnimations];
[imageView release];
}
your animationDidStopSelector will be just like:
-(void)animationDidStop:(id)sender {
//This is almost similar to collision detection, you can do something here
}
imageView is a local variable to the function createNewImageView and hence cannot be accessed by myRunloop
If you have declared imageView as an IBOutlet
you can set the image like this
UIImage *image = [UIImage imageNamed:#"abouffer_03.png"];
imageView.image = image
In Interface (.h file) declare like this
UIImageView *imageView;
And In your createNewImageView() method.Use the
imageView = [[UIImageView alloc] initWithImage:image];
You can assign a tag to the image view so you can find it later in the other method:
[imageView setTag:1];
// in myRunloop
UIImageView* imageView = [[self view] viewWithTag:1];
In my application after the view load, an image should appear from left to right.
I am writing this code in in viewdidload or viewwillappear:
UIImage *image = [UIImage imageNamed:#"PG05(REV).jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
for (int i=-1024; i<=0; i++) {
NSLog(#"i: %d",i);
sleep(5);
imageView.frame = CGRectMake(i,0, 1024, 768);
NSLog(#"done");
[self.view addSubview:imageView];
}
[imageView release];
But problem is that, before loading view it executes the above code than loads the view, so that it seems that view loaded and a static image is there.
But my requirement is that first view load completely then image should display from left to right.
Please help me out.
First of all, you should not call the -(void)addSubview: inside your for loop. You just need to call it once.
Secondly, if you want to animate your imageView from left to right, UIView class provides great functionalities for this using blocks.
Your code should look like this :
UIImage *image = [UIImage imageNamed:#"PG05(REV).jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(-1024, 0, 1024, 768);
[self.view addSubview:imageView];
[imageView release]; //Your imageView is now retained by self.view
//Animation
[UIView animateWithDuration:2.0
animations:^(void) {
imageView.frame = CGRectMake(0, 0, 1024, 768);
}];
The animateWithDuration: method will handle the animation timer for you, just set the duration argument according to your needs.
You can use a function and call it using timer method.
timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(moveImage) userInfo:nil repeats:NO];
-(void)moveImage
{
//Your condition
}
This is a job for UIView animations.
Put your imageView down at -1024 left, then go:
[imageView animateWithDuration:5 animations:^{
[imageView.frame = CGRectMake(0,0, 1024, 768)];
}];
Ta-da! A five second animation of your image sliding to the right.
Check out the animation methods of UIView (of which UIImageView is a subclass):
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html
I'm ATTEMPTING to learn UIScrollview using Apple's Docs and their sample code http://developer.apple.com/iphone/library/samplecode/Scrolling/index.html but something SO simple is escaping me.
How do you tell what image is currently on the screen, so that if I selected one of the images in the horizontal scrolling view, how would I get the filename of the image, or even a pointer in the array, to then do something further with the image?
I thought with Page Control enable I might be able to find a page # and map it to the image. I thought about counting deceleration to count pages, but a flick no full enough will increment it and give a false number.
The last thing I could think of is to get contentOffSet and divide by image size which will give a 1, 2, 3 and I could point to the array (too tired to try tonight... thought I might ask before I waste a lot more time ;-) ).
Any other ideas? I thought there would be a method somewhere that they use in the photo album app.
PS: Here's the code:
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
//NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Card %d.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
This was easy after a good sleep!
CGPoint p = scrollView1.contentOffset;
NSLog(#"x = %f, y = %f", p.x, p.y);
Now just divide by 320 (if horizontal and full screen image) and add 1 (because it starts at 0).
Hope this helps someone else!
Paul