I am trying to Display a an Image when the user Taps on the UIImageView. But before the user Taps the UIImageView the Image should not be shown, and after a few seconds the Image should disappear again. Does anyone know how to do this? I read through couple of Threads but they do not work with the latest Xcode as it appears. Thanks for your help and time.
Udate
Well, my code now looks like this:
-(void)imageTapped:(UITapGestureRecognizer*)recognizer
{
recognizer.view.alpha=0.0;
((UIImageView*)recognizer.view).image = [UIImage imageNamed:#"twingo_main.png"];
[UIView animateWithDuration:1.0 delay:2.0 options:0 animations:^{
recognizer.view.alpha=1.0;
} completion:^(BOOL finished) {
recognizer.view.alpha=0.0;
((UIImageView*)recognizer.view).image = nil;
recognizer.view.alpha=1.0;
}];
}
- (void)viewDidLoad
{
UIImageView *hiddenImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 30, 20, 20)];
hiddenImage.userInteractionEnabled=YES;
[hiddenImage addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:)]];
[self.view addSubview:hiddenImage];
Well, now my question is, how do I need to set up the UIImageView in the View Controller?
In your UIViewController's viewDidLoad method:
...
UIImageView *hiddenImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 30, 20, 20)];
hiddenImage.userInteractionEnabled=YES;
[hiddenImage addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:)]];
[self.view addSubview:hiddenImage];
...
UITapGestureRecognizer Handler:
-(void)imageTapped:(UITapGestureRecognizer*)recognizer
{
recognizer.view.alpha=0.0;
((UIImageView*)recognizer.view).image = [UIImage imageNamed:#"imageName"];
[UIView animateWithDuration:1.0 delay:2.0 options:0 animations:^{
recognizer.view.alpha=1.0;
} completion:^(BOOL finished) {
recognizer.view.alpha=0.0;
((UIImageView*)recognizer.view).image = nil;
recognizer.view.alpha=1.0;
}];
}
Set the image in the UIImageView to nil initially. Add a tap gesture recognizer to the UIImageView that, when fired, sets the image and starts a timer. When the timer completes, set your image back to nil.
Here is an another way to handle above with NSTimer..
-(void)imageTapped:(UITapGestureRecognizer*)recognizer
{
CustomPopUpView *lCustomPopUpView = [[CustomPopUpView alloc]init];
//Added your imageview to Custom UIView class
[self.window addSubview:lCustomPopUpView];
[self.window bringSubviewToFront:lCustomPopUpView];
mPopupTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(closePopUp) userInfo:Nil repeats:FALSE];
}
- (void)closePopUp{
if (mPopupTimer != nil) {
[mPopupTimer invalidate];
mPopupTimer = nil;
}
for (UIView *lView in self.window.subviews) {
if ([lView isKindOfClass:[CustomPopUpView class]]) {
[lView removeFromSuperview];
}
}
}
Its better to have view behind the UIImageView to handle the TapGesture.
But here is the fix for you code:
Add this to viewDidLoad method to setup you image view to handle tap gesture
//By default the UserInteraction is disabled in UIImageView
[self.testImageView setUserInteractionEnabled:YES];
UITapGestureRecognizer *tapgesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(ShowImage:)];
tapgesture.numberOfTapsRequired=1;
tapgesture.numberOfTouchesRequired=1;
[self.testImageView addGestureRecognizer:tapgesture];
here is the method handle the gesture event
-(void)ShowImage:(UIGestureRecognizer*)recognizer{
recognizer.view.alpha=0.0;
((UIImageView*)recognizer.view).image = [UIImage imageNamed:#"clone.jpg"];
[UIView animateWithDuration:1.0 delay:0 options:0 animations:^{
recognizer.view.alpha=1.0;
} completion:^(BOOL finished) {
//[self performSelector:#selector(hideImage:) withObject:recognizer.view afterDelay:10];
[UIView animateWithDuration:1.0 delay:3.0 options:0 animations:^{
recognizer.view.alpha=0.0;
} completion:^(BOOL finished) {
((UIImageView*)recognizer.view).image=nil;
((UIImageView*)recognizer.view).alpha=1.0;
}];
}];
}
If you set the alpha of view to 0, then your view will not receive any touch event further. So its best practice to set it again to 1.0 after removed the image from UIImageView.
You may want to consider using a UIButton. Detecting touches with these is easy - as is changing their image.
You could also subclass UIControl (see http://www.raywenderlich.com/36288/how-to-make-a-custom-control).
Related
I'm making a very simple game. I have a UIButton and an UIImageView. What I'm trying to do is that when the user presses the button, it will change the image to another image and then back to the original image, to simulate an animation (Character moving)
I have this code:
file.m
{
IBOutlet UIImageView *image1;
IBOutlet UIButton *button;
}
-(IBAction)button:(id)sender;
file.h
-(IBAction)button:(id)sender{
[UIView animateWithDuration:1.0f
animations:^{
image1.alpha = 0.1f;
} completion:^(BOOL finished) {
image1.image = [UIImage imageNamed:#"image2.png"];
[UIView animateWithDuration:0.2f
animations:^{
image1.alpha = 1.0f;
} completion:^ (BOOL finished) {
image1.image = [UIImage imageNamed:#"image1.png"];
}];
}];
}
When I open the iOS simulator and press the button, the image dissolves, then reappears and then does the animation. The problem is that I don't want it to dissolve, I just want to show the animation. How do I prevent this from happening? Is it because I'm using alpha properties?
Thank you!
I used the following code to do what I think is what you need (shown here: https://www.dropbox.com/s/vtcyw0n257tgihx/fade.mov?dl=0):
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(test)];
iv = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 150, 150)];
iv.image = [UIImage imageNamed:#"red"];
[self.view addSubview:iv];
}
- (void)test {
[UIView animateWithDuration:1.0f animations:^{
iv.alpha = 0.0f;
} completion:^(BOOL finished) {
iv.image = [UIImage imageNamed:#"blue"];
[UIView animateWithDuration:1.0f animations:^{
iv.alpha = 1.0f;
} completion:^ (BOOL finished) {
[UIView animateWithDuration:1.0f animations:^{
iv.alpha = 0.0f;
} completion:^ (BOOL finished) {
iv.image = [UIImage imageNamed:#"red"];
[UIView animateWithDuration:1.0f animations:^{
iv.alpha = 1.0f;
} completion:nil];
}];
}];
}];
}
You need to break it down into four parts. First you need to fade the original image out, change it to the second image, fade the second image in, fade the second image out, change back to the original image, then fade it back in.
I implemented the feature to display a fullscreen image when it is tapped. However this only enlarge the image but does not show it with a black background (the other elements of the view are still in the bakcground). How can I do this?
//Setup touch up inside of the imageview (in viewdidload)
userPictImageView.userInteractionEnabled = YES;
userPictImageView.contentMode = UIViewContentModeScaleAspectFit;
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewFullScreenTouchHandler:)];
tapper.numberOfTapsRequired = 1;
[userPictImageView addGestureRecognizer:tapper];
//present a full screen image (without black background)
-(IBAction)imageViewFullScreenTouchHandler:(id)sender {
//goto new ViewController and set the image
UIImageView *imageView = userPictImageView;
if (!imageIsFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = imageView.frame;
blackView=[[UIView alloc]initWithFrame:self.view.frame];
[blackView setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:blackView];
CGRect frame = self.view.frame;
[imageView setFrame:frame];
[blackView addSubview:imageView]; }
completion:^(BOOL finished){
imageIsFullScreen = TRUE;
}];
return;
}
else{
self.view.backgroundColor = [UIColor clearColor];
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[imageView setFrame:prevFrame];
}completion:^(BOOL finished){
imageIsFullScreen = FALSE;
}];
return;
}
}
You could change to UIViewContentModeScaleToFill, or, probably better, build a UIView with a black background whose frame matches the view frame. Make the image view a subview of that black view.
I'd do it something like this. Create a method that I can call to zoom and unzoom the imageView. To zoom, build a background view and attach the image. To unzoom, do the reverse, and then destroy the background view.
Since the background view will be full screen, attach a gesture recognizer to it so the user can tap to dismiss.
- (void)setUserPictImageViewZoomed:(BOOL)zoom animated:(BOOL)animated {
UIView *blackView = [self.view viewWithTag:128];
BOOL isZoomed = blackView != nil;
// if our current state (isZoomed) matches the desired state (zoomed), then we're done
if (isZoomed == zoom) return;
NSTimeInterval duration = (animated)? 0.3 : 0.0;
if (zoom) {
blackView = [[UIView alloc] initWithFrame:self.view.frame];
blackView.backgroundColor = [UIColor blackColor];
blackView.tag = 128;
blackView.alpha = 0.0;
[self.view addSubview:blackView];
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(unzoom:)];
[blackView addGestureRecognizer:tapGR];
UIImageView *zoomImageView = [[UIImageView alloc] initWithImage:self.userPictImageView.image];
zoomImageView.contentMode = UIViewContentModeScaleAspectFit;
zoomImageView.tag = 129;
zoomImageView.frame = [self.userPictImageView convertRect:self.userPictImageView.frame toView:blackView];
[blackView addSubview:zoomImageView];
[UIView animateWithDuration:duration animations:^{
zoomImageView.frame = blackView.bounds;
blackView.alpha = 1.0;
}];
} else {
UIImageView *zoomImageView = (UIImageView *)[blackView viewWithTag:129];
[UIView animateWithDuration:duration animations:^{
zoomImageView.frame = self.userPictImageView.frame;
blackView.alpha = 0.0;
} completion:^(BOOL finished) {
[blackView removeFromSuperview];
}];
}
}
- (void)unzoom:(UIGestureRecognizer *)gr {
[self setUserPictImageViewZoomed:NO animated:YES];
}
I tested this quickly in a simulator and it looked pretty slick.
I'm trying to show a fullscreen picture from a smaller one included in a custom UITableViewCell. My code is highly linked to this article
By the way, in this example, the frame : [[UIScreen mainScreen] bounds]is not the good one for me. It's the an UIScrollView's bounds that I've got. I this to add the main screen through a variable inside the cell directly when each cell is created. So I've customized the previous example like this :
//viewDidLoad
self.globalView.frame = [[UIScreen mainScreen] bounds];
//cellForRowAtIndexPath
[cell setFullScreenView:self.globalView];
//fullScreenMethod
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = imageView.frame;
[imageView setFrame:self.fullScreenView.frame];
}completion:^(BOOL finished){
isFullScreen = YES;
}];
return;
}
My problem is that the imageView's new frame is not a full screen but still the UIScrollView's one.
Thank you for your help !
Best approach is create one temporary UIImageView and Show it in full screen,
For animation simply add the temporary UIImageView to location where the image view exists and animate it to full-screen and do revers for normal
Add tap gesture to UIImageView and add this bannerTapped as selector
//This will create a temporary imaget view and animate it to fullscreen
- (void)bannerTapped:(UIGestureRecognizer *)gestureRecognizer {
NSLog(#"%#", [gestureRecognizer view]);
//create new image
temptumb=(UIImageView *)gestureRecognizer.view;
//fullview is gloabal, So we can acess any time to remove it
fullview=[[UIImageView alloc]init];
[fullview setContentMode:UIViewContentModeScaleAspectFit];
[fullview setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"bckgrd.png"]]];
fullview.image = [(UIImageView *)gestureRecognizer.view image];
CGRect point=[self.view convertRect:gestureRecognizer.view.bounds fromView:gestureRecognizer.view];
[fullview setFrame:point];
[self.view addSubview:fullview];
[UIView animateWithDuration:0.5
animations:^{
[fullview setFrame:CGRectMake(0,
0,
self.view.bounds.size.width,
self.view.bounds.size.height)];
}];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(fullimagetapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[fullview addGestureRecognizer:singleTap];
[fullview setUserInteractionEnabled:YES];
}
//This will remove the full screen and back to original location.
- (void)fullimagetapped:(UIGestureRecognizer *)gestureRecognizer {
CGRect point=[self.view convertRect:temptumb.bounds fromView:temptumb];
gestureRecognizer.view.backgroundColor=[UIColor clearColor];
[UIView animateWithDuration:0.5
animations:^{
[(UIImageView *)gestureRecognizer.view setFrame:point];
}];
[self performSelector:#selector(animationDone:) withObject:[gestureRecognizer view] afterDelay:0.4];
}
//Remove view after animation of remove
-(void)animationDone:(UIView *)view
{
//view.backgroundColor=[UIColor clearColor];
[fullview removeFromSuperview];
fullview=nil;
}
It can't take a full screen frame because its parent view is the scrollView. Either show view modally or somehow move imageView directly under view controller's main view.
This has been asked before but none of the answers are straightforward enough to help little old me.
What exactly does .isAnimating in an UIIimage view do? And how to properly use it?
I am emulating the tap to focus animation in the iPhone camera (yellowish square that pops up and then shrinks when you tap on the preview). That works fine, but I want it to not happen multiple times if it is already animating. This code does the animation but multiple taps gives multiple animationed squares. I suspect it is not just .isAnimating but I'm also doing something else wrong because I tried it with my own boolean too and that fails.
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
UIImage *focusSquareImage = [UIImage imageNamed:#"yellowFocusSquare"];
UIImageView *tmpView = [[UIImageView alloc] initWithImage:focusSquareImage];
if (!(tmpView.isAnimating))
{
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
NSLog(#"in animation isAnimating %hhd", tmpView.isAnimating);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
}];
}
NSLog(#"done animating isAnimating %hhd", tmpView.isAnimating);
[tmpView release];
}
If there is question where this has a solid answer, that would be great.
EDIT - here is the working code.
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
if (animationInProgress)
return;
animationInProgress = true;
UIImageView *tmpView = [[UIImageView alloc] initWithImage:sp_ui->focus_square];
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
animationInProgress = false;
}];
[tmpView release];
}
I suspect on your code. On your tapping on method focusSquarePopUp: you create new instances of tmpView and focusSquareImage and it adding on self view. That why you found number of animated square equal to number of tap. When you create new instance of those variable then sure isAnimating is firstly you got NO value and it enter animation block code.
Why not you create instance of tmpView and focusSquareImage in .h file of class?? In fact its problem of variable declarations and scope of variables.
Your code should be like this,
Declare instance in animation class (i.e. self.view) .h file
UIImage *focusSquareImage;
UIImageView *tmpView;
Now in .m file viewDidLoad method,
in viewDidLoad
focusSquareImage = [UIImage imageNamed:#"yellowFocusSquare"];
tmpView = [[UIImageView alloc] initWithImage:focusSquareImage];
Your animation method implementation should be,
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
if (!(tmpView.isAnimating))
{
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
NSLog(#"in animation isAnimating %hhd", tmpView.isAnimating);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
[tmpView release];
}];
}
}
Another option of method implementation,
-(void)focusSquarePopUp:(CGPoint)touchPoint;
{
if(!tmpView){
focusSquareImage = [UIImage imageNamed:#"yellowFocusSquare"];
tmpView = [[UIImageView alloc] initWithImage:focusSquareImage];
if (!(tmpView.isAnimating))
{
tmpView.center = touchPoint;
tmpView.opaque = YES;
tmpView.alpha = 1.0f;
[self.view addSubview:tmpView];
tmpView.hidden = NO;
// shrink to half size in .3 second
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
tmpView.transform = CGAffineTransformMakeScale(.5, .5);
NSLog(#"in animation isAnimating %hhd", tmpView.isAnimating);
} completion:^(BOOL finished) {
// Once the animation is completed hide the view for good
tmpView.hidden = YES;
[tmpView release];
tmpView = nil;
}];
}
}
}
isAnimating is UIImageView property and it has nothing to do with UIView animation methods
isAnimating is used when you want a UIImageView to alternate between multiple images. For example in the following code the UIImageView display 3 images and alternate between them
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
UIImage *image1 = [UIImage imageNamed:#"image1.png"];
UIImage *image2 = [UIImage imageNamed:#"image2.png"];
UIImage *image3 = [UIImage imageNamed:#"image3.png"];
imageView.animationImages = #[image1, image2, image3];
imageView.animationDuration = 1;
NSLog(#"isAnimating %d",imageView.isAnimating); // isAnimating 0
[imageView startAnimating];
NSLog(#"isAnimating %d",imageView.isAnimating); // isAnimating 1
[self.view addSubview:imageView];
Your case is completely different you are using UIView animation blocks and to know if the animation in its block is finished or not you will need to add a Boolean flag instance variable animationFinished and set it to YES in the completion block of the animation
I'm using the following code to zoom/enlarge an image from within a table view. I would like it to enlarge out to full screen. the current problem is that when it enlarges it enlarges only within the table cell (and as a result is partially hidden beneath the next table cell) instead of the full view.
-(void)zoomPhotoMethod :(id) sender
{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
NSLog(#"Tag = %d", gesture.view.tag);
userSubmittedImageView = (UIImageView *)gesture.view;
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = userSubmittedImageView.frame;
UIView *popupImageViewForTableCell = [[UIView alloc] initWithFrame: CGRectMake ( 0, 0, 320, 500)];
[userSubmittedImageView setFrame:[popupImageViewForTableCell bounds]];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[userSubmittedImageView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;;
}];
return;
}
}
updated code:
-(void)zoomPhotoMethod :(id) sender
{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
NSLog(#"Tag = %d", gesture.view.tag);
userSubmittedImageView = (UIImageView *)gesture.view;
if (!isFullScreen) {
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
//save previous frame
prevFrame = userSubmittedImageView.frame;
newView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)];
[self.view addSubview:newView];
UIView *popupImageViewForTableCell = [[UIView alloc] initWithFrame: CGRectMake ( 0, 0, 320, 500)];
[userSubmittedImageView setFrame:[popupImageViewForTableCell bounds]];
[newView addSubview:userSubmittedImageView];
[userSubmittedImageView setFrame:[newView bounds]];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.3 delay:0 options:0 animations:^{
[userSubmittedImageView setFrame:prevFrame];
[newView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;;
}];
return;
}
}
What's happening is that you are still a subview of the tableview cell, so it's not going to be able to go outside of those bounds without being clipped.
To do what you want to do, you're going to have to:
Create a new UIImageView outside of your table view (add it as a subview outside of the tableview).
Set the image in the image view to the same image that you have in the tableview cell.
Start it at the same size and position as your tableview cell image.
Animate it up to where you want it.
When it's time to remove it, move it back down to the original tableview cell image.
Discard the imageview.
One way would be to use a copy of the image and place it outside the cell just above your original and animate this second image to full screen.
Another way would be to increase the tableView rowHeight and reload the section.