There is UICollectionView with cell. By tapping on the cell subview should be added.
Everything works, but... if I quickly tap second or third time, it add two or three subviews...
So how to properly do that?
This is the code of didSelectItemAtIndexPath:
recipeDetailView = [[RecipeDetailViewController alloc] initWithNibName:#"RecipeDetailViewController" bundle:nil];
[recipeDetailView.view setBackgroundColor: [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgRecipe.jpg"]]];
[recipeDetailView.view setFrame: myFrame];
[UIView animateWithDuration:0.3
delay:0.0
options: UIViewAnimationOptionCurveLinear
animations:^{
[recipeDetailView.view setFrame: CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:recipeDetailView.view];
[self addChildViewController:recipeDetailView];
[recipeDetailView didMoveToParentViewController:self];
}
completion:^(BOOL finished){
[recipeDetailView slideViewAdd];
}];
In didSelectItemAtIndexPath just add all your code into this.
if(recipeDetailView == nil)
{
//copy all your codes from above question.
}
And when your are removing the view just set the recipeDetailView to nil.
recipeDetailView = nil;
Either disable user interaction for a short time after the tap is detected.
Or, use a gesture recognizer to detect the tap, and another for multiple taps, and require the multiple tap recognizer to fail before the single tap recognizer fires.
Related
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
I want to start the UIPanGestureRecognizer right after adding it to a screenshot. Because the screenshot is created through code, when an item has been highlighted, the user won't press on the screen again. So... How do I start the recognizer programmatically?
UIView *snapshot = [cell snapshotViewAfterScreenUpdates:NO];
//use the cell to map the snapshot frame to the window because this does a perfect job of accounting for table offset, etc. Other methods put the view a little to the side or way off
CGRect newFrame = snapshot.frame;
newFrame.origin = [cell convertPoint:newFrame.origin toView:self.view.window];
[snapshot setFrame:newFrame];
[HelperMethods shadowForView:cell color:[UIColor blackColor] offset:CGSizeMake(1, 1) opacity:.7 radius:snapshot.frame.size.width/4];
//[self.view addSubview:snapshot];
newFrame.origin.y -=10;
//move the frame a little to let user know it can be moved
[UIView animateWithDuration:.2 animations:^{
[snapshot setFrame:newFrame];
}];
//add a long press that kills the tap if recognized
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(userCellDragged:)];
[pan setMinimumNumberOfTouches:1];
[pan setMaximumNumberOfTouches:1];
[cell addGestureRecognizer:pan];
You can always call the method on its own.
For example, you've added the selector
- (void) userCellDragged:(UIPanGestureRecognizer)sender;
For your pan gesture recognizer.
You could call this from anywhere in the view by simply adding
[self userCellDragged:nil];
Remember to add a parameter to this method something like:
if (sender == nil) {
// Triggered programmatically
}
else {
// proceed as normal
}
I am attempting a simple UIView animation in the viewDidLoad or viewDidAppear method but it doesn't animate.
UIImage *bluredScreenshot = [self.parentViewControllerScreenshot applyBlur];
[UIView transitionWithView:self.screenshotView duration:3.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
self.screenshotView.image = bluredScreenshot;
} completion:nil];
Simple cross dissolving two images. When ran from viewDidLoad or viewDidAppear the image changes but isn't animated.
But lets say I run the animation from a method after I press a button, it will animate. Why? Seem strange.
Is it possible to make it from the viewDidLoad method? How would you solve this?
Thanks.
You need to fade in the screenshot. If you're using two images, you'll need to place one image view atop the other.
pop this inside viewDidAppear: after calling [super viewDidAppear:animated];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.screenshotView.frame];
[self.view addSubview:imageView];
[imageView setAlpha:0.0f];
imageView = blurredScreenshot;
[UIView animateWithDuration:0.3f animations:^{
[imageView setAlpha:1.0f];
} completion:^(BOOL finished){
self.imageView.image = blurredScreenshot;
[imageView removeFromSuperview];
}];
when the view is loading you can't animate because there isn't anything to animate. Try in viewdidapear: and Don't use transition
[UIView animateWithDuration:3.
delay:0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.screenshotView.image = bluredScreenshot;
}
completion:nil];
Just a reminder, sometimes your problem can be caused by not calling:
self.layoutIfNeeded()
I wrote a custom UITableViewCell - image view, button and three labels now I am trying to add some animations to it. So once I tap the button, it fades away and the spinner replaces the button. After two seconds the cell is overlaid with a red color, as a subview of cell fades in, then the indicator is removed and and red overlay starts fading back out. As well the button I previously removed fades back in.
(I could not phrase it a better way :P )
The method is :
-(void)rentButtonPressed:(id)sender
{
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[indicator startAnimating];
indicator.center = self.rentButton.center;
[UIView animateWithDuration:0.2
animations:^{self.rentButton.alpha = 0.0;}
completion:^(BOOL finished){
[self.rentButton removeFromSuperview];
[self addSubview:indicator];
}
];
UIView *overlay = [[UIView alloc] initWithFrame:self.backgroundImage.frame];
overlay.alpha = 0.0;
overlay.backgroundColor = [UIColor redColor];
[self.contentView addSubview:overlay];
[UIView animateWithDuration:0.4
delay:2.0
options:UIViewAnimationCurveEaseInOut
animations:^{
[indicator removeFromSuperview];
overlay.alpha = 0.4;
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.4
animations:^{ overlay.alpha = 0.0; }
completion:^(BOOL finished)
{
[overlay removeFromSuperview];
}
];
[self.contentView addSubview:self.rentButton];
[UIView animateWithDuration:0.4 animations:^{ self.rentButton.alpha = 1.0;}];
[self.delegate didTryToRentMovieAtCell:self];
}
];
}
So the code does fade out the button, replace it with spinner and fades in the red overlay. The problem is, the red overlay does not fade away, but disappears same with the button, instead of fading in, it just appears.
During your animation, you are changing the view hierarchy by adding and removing subviews. The UIView class method animateWithDuration:animations:completion is intended only animating property changes in a view, and not for changing the view hierarchy.
Try using the UIView class method transitionWithView:duration:options:animations:completion: instead, and use the cell's content view as the "container."
This documentation is helpful in distinguishing between animating view property changes and animating view transitions, specifically the section "Changing the Subviews of a View":
http://developer.apple.com/library/ios/#documentation/windowsviews/conceptual/viewpg_iphoneos/animatingviews/animatingviews.html
It's my first post on stackoverflow. I'm a iOS developer newbie and I'm not a native English speaker, so I will do my best to explain my problem.
Problem:
I have added two views to my AppDelegate window and I want to flip from one to the other using:
UIView transitionFromView:toView:
The first view (MainScreenView) has its own ViewController. On the MainScreenView .xib file I have a button with an action that calls the method "goShow" implemented in my AppDelegate. In that method I use UIView transitionFromView:toView: to transition to the second view. So far everything is working fine.
My second view (a scrollview) is declared programmatically in my AppDelegate and has a bunch of pictures inside it (picturesViewController) and on top of those, has a UIPinchGestureRecognizer.
I'm using a gesture recognizer to flip back to my MainScreenView. That is where the problem is. When I do a pinch gesture on the scrollview the MainScreenView.view appears immediately, before the animation, so the flip animation looks wrong.
The code I'm using is:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
mainScreen = [[MainScreenViewController alloc] initWithNibName:#"MainScreenViewController" bundle: [NSBundle mainBundle]];
CGRect frame = self.window.bounds;
int pageCount = 10;
scrollView = [[UIScrollView alloc] initWithFrame:frame];
scrollView.contentSize = CGSizeMake(320*pageCount, 480);
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = FALSE;
scrollView.showsVerticalScrollIndicator = FALSE;
scrollView.delegate = self;
[...] 'While' adding pictures to de scrollView
UIPinchGestureRecognizer *twoFingerPinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(goBackToMain)] autorelease];
[scrollView addGestureRecognizer:twoFingerPinch];
[self.window addSubview: scrollView];
[scrollView setHidden:TRUE];
[self.window addSubview: mainScreen.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void) goShow{
[UIView transitionFromView:mainScreen.view
toView:scrollView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView commitAnimations];
}
-(void) goBackToMain {
[UIView transitionFromView:scrollView
toView:mainScreen.view
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView commitAnimations];
}
I'm using show/hide views instead of addSubview/removeFromSuperView because I tried the add and remove and got an app crash in the pinch gesture, exactly in same step that is failing the animation. Probably it is the same error, but I'm unable to find the reason for this. Any help would be appreciated.
Thanks.
Ok. With Adrian's help, here's the UIPinchGesture code that solved my problem:
[...]
UIPinchGestureRecognizer *twoFingerPinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(goBackToMain:)] autorelease];
[scrollView addGestureRecognizer:twoFingerPinch];
-(void)goBackToMain:(UIPinchGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded)
{
[UIView transitionFromView:scrollView
toView:mainScreen.view
duration:0.4
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:nil];
[UIView commitAnimations];
}
First, you cannot mix the old method beginAnimation commitAnimation combination with the new block method transitionFromView.
Second, when using block method animation, make sure you use a container (probably a UIView) that will be the parent of the two views you want to switch. Without the container you will be animating the whole view instead. Make sure the container have the same size as the subviews that will switch.
Example:
[container addSubView:frontView];
[container addSubView:backView];
[self.view addSubView:container];
[UIView transitionFromView:backView toView:frontView duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
Read more about animations in iOS.
In your example you forgot [UIView beginAnimations].