Animations don't work when scrolling UIScrollView - ios

I have a UIScrollView that has a bunch of items in it, similar to a facebook feed. In that feed I have a bunch of images that are being loaded from the internet. When the images are loaded they fade in. The problem is that if I am scrolling the scroll view, then the image animation to fade in doesn't occur until my finger is lifted off the scrollview. Is there any way to update the subviews of the UIScrollView view while scrolling?
-(void)loadStuff:(DipticView*)diptic{
//DipticView is a UIView subclass that holds the imageview and some other information
ConnectionManager *conman = [[ConnectionManager alloc] init];
WebImage *webimage = [diptic.item.images firstObject]; //webimage holds the imageurl and the image
[conman getImageWithURL:webimage.image_URL inBackgroundWithBlock:^(NSString *error, id image) {
webimage.image = image;
diptic.imageView.image = image;
diptic.imageView.alpha = 0;
diptic.userInteractionEnabled = NO;
[UIView animateWithDuration:.4 animations:^{
diptic.imageView.alpha = 1;
} completion:^(BOOL finished) {
diptic.userInteractionEnabled = YES;
}];
//The diptics are all subviews of the scrollview.
}];
}

dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:.4 animations:^{
diptic.imageView.alpha = 1;
} completion:^(BOOL finished) {
diptic.userInteractionEnabled = YES;
}];
});
But I'm not sure that this method can work well with animateWithDuration.

Related

How to put UICollectionView and button in UIPageControl in ios?

This is my collectionview when i swipe it scrolls,
i have putted UICollectionView and button in UIPageControl, when swipe UICollectionView scrolling, and button view not scrolling smoothly as works as normal UIPageControl
I'm not sure but I think it has something to do with your CATransitions
Try changing the last piece of the method so you use UIView animations instead of CATransitions:
if(pageControl.currentPage==pageControl.numberOfPages-1)
{
[UIView animateWithDuration:0.2
animations:^{
dayRadialCollection.alpha = 0.0f;
addWeek.alpha = 1.0f;
removeWeek.alpha = 1.0f;
} completion:^(BOOL finished) {
}];
}
else {
[UIView animateWithDuration:0.2
animations:^{
dayRadialCollection.alpha = 1.0f;
addWeek.alpha = 0.0f;
removeWeek.alpha = 0.0f;
} completion:^(BOOL finished) {
}];
}
There is also no need to hide the elements, as alpha 0.0f will not show them anyway.

Advice on Collectionview scenario

Need some advice on how to approach a scenario using a Collectionview. In short, the app has a CV displaying images where you can tap a cell with a thumbnail of an image and it will then display a fullscreen view of that image. I'm accomplishing this by instantiating a new UIView (not from storyboard) inside didSelectItemAtIndexPath. So the fullscreen view of the image from the cell is just a new UIView triggered from tapping the cell and I set the view's image to be the same as the cell's image...simple enough. The fullscreen view also has a button that relates to each image. Tapping the fullscreen image closes the image and goes back to the CV. All of this works perfectly.
However, I just realized that I would also like to be able to swipe through all the images while in fullscreen mode...basically very similar to how the iOS photo album works. I was able to write some code pretty quickly to do this by adding a swipe gesture to didSelectItemAtIndexPath and set the action selector to a method to handle the swipes, which worked. However, the result of this was really just changing the image for the original cell selected (tapped). So I'm not able to keep track of the selected cell while swiping through the images in fullscreen mode.
So I need advice on how to approach this. I know there has to be examples out there for something like this, but I was unable to find any. Does anyone have any advice on how I should implement this? Thanks!
Code from didSelectItemAtIndexPath...
self.fullScreenImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width-10, self.view.bounds.size.height-15)];
self.fullScreenImage.contentMode = UIViewContentModeScaleAspectFit;
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleRightSwipe:)];
[rightSwipe setDirection:UISwipeGestureRecognizerDirectionRight];
[self.fullScreenImage addGestureRecognizer:rightSwipe];
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleLeftSwipe:)];
[leftSwipe setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.fullScreenImage addGestureRecognizer:leftSwipe];
if (!self.isFullScreen) {
self.fullScreenImage.transform = CGAffineTransformMakeScale(0.1, 0.1);
__weak BaseViewController *weakSelf = self;
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
NSLog(#"Starting animiation!");
weakSelf.view.backgroundColor = [UIColor blackColor];
weakSelf.myCollectionView.backgroundColor = [UIColor blackColor];
weakSelf.fullScreenImage.center = self.view.center;
weakSelf.fullScreenImage.backgroundColor = [UIColor blackColor];
weakSelf.fullScreenImage.image = [UIImage imageWithContentsOfFile:coffeeImageData.imageURL.path];
weakSelf.fullScreenImage.transform = CGAffineTransformIdentity; // zoom in effect
[weakSelf.view addSubview:self.fullScreenImage];
[weakSelf.fullScreenImage addSubview:likeButton]; // add the button to the view
}completion:^(BOOL finished){
if (finished) {
NSLog(#"Animation finished!");
weakSelf.isFullScreen = YES;
}
}];
return;
}
Handling the swipe gesture from...
- (void)handleLeftSwipe:(UISwipeGestureRecognizer *)sender {
// make sure indexForSwiping is not > than size of array
if (self.indexForSwiping != [self.imageLoadManager.coffeeImageDataArray count]-1) {
self.indexForSwiping += 1;
NSString *cacheKey = self.allCacheKeys[self.indexForSwiping];
if (cacheKey) {
[self.imageCache queryDiskCacheForKey:cacheKey done:^(UIImage *image, SDImageCacheType cacheType) {
if (image) {
[UIView animateWithDuration:1.0 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.fullScreenImage.image = image;
} completion:^(BOOL finished) {
NSLog(#"swiping");
}];
}
}];
}
}
}
This framework already have such functionality, so you can look into source code to understand how it works...
https://github.com/mwaterfall/MWPhotoBrowser
I would have the view be part of the viewController and not only part of your function. Then, have the viewController manage the swipe, image, and location of the image. When your collectionView is tapped, set the location in your viewController so that when a swipe is caught you can increment by one and update your view with the new image. Let me know if that wasn't clear enough and I can try clarifying

How to animate deletion of a label?

I have a view controller that have a scroll view that bounce horizontally , and in this scroll view I have a label.
I can now hold the label and scroll it down, and if I release it will bounce up back.
What I want is that: When I scroll the view y coordinate (using myScrollView.contentOffset.y) to some value, lets say -33 and under I can release my fine and the label will animate to the bottom of the screen and disappear, and now I can set the label to be a new value, and It will animate from top to the label original position.
Here a photo of how the view controller looks like:
And this is the relevant method I already implemented (powered by #rebello95):
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (self.myScrollView.contentOffset.y <= -73) {
[UIView animateWithDuration:0.3 animations:^{
self.homeLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[self.homeLabel removeFromSuperview];
self.homeLabel = nil;
}];
}
NSLog(#"%f", self.myScrollView.contentOffset.y);
}
Now I want it to slide to the bottom of the page and fade.
thanks!
EDIT: The animation now moves the label to the bottom of the view controller then fades it out.
You can use an animation block to move the label, then put another block inside the completion block to fade out the label, then remove it after the animation completes.
Example:
[UIView animateWithDuration:0.3 animations:^{
[self.myLabel setFrame:CGRectMake(self.myLabel.frame.origin.x, self.view.frame.size.height - self.myLabel.frame.size.height, self.myLabel.frame.size.width, self.myLabel.frame.size.height)];
self.labelRemoving = YES;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^{
self.myLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[self.myLabel removeFromSuperview];
self.myLabel = nil;
self.labelRemoving = NO;
}];
}];
Sidenote: You should probably be using <= instead of == in your if statement to achieve your desired results. In addition, you may want to set a flag to indicate that your label is being removed (since that method will inevitably be called multiple times). Something like this:
//.h
#property (nonatomic, assign) BOOL labelRemoving;
//.m
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (self.myScrollView.contentOffset.y <= -33 && !self.labelRemoving) {
[UIView animateWithDuration:0.3 animations:^{
[self.myLabel setFrame:CGRectMake(self.myLabel.frame.origin.x, self.view.frame.size.height - self.myLabel.frame.size.height, self.myLabel.frame.size.width, self.myLabel.frame.size.height)];
self.labelRemoving = YES;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^{
self.myLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[self.myLabel removeFromSuperview];
self.myLabel = nil;
self.labelRemoving = NO;
}];
}];
}
NSLog(#"%f", self.myScrollView.contentOffset.y);
}

Show UIImageView on screen Tap

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).

IOS: How to detect animation is in progress

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

Resources