How can you zoom in on a UICollectionViewCell so that it will be displayed full screen? I have extended UICollectionViewFlowLayout and in my view controller when a cell is tapped I'm doing this:
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
NSLog(#"Selected cell %#", selectedIndexPath);
Not really sure where to go from here. Should the UICollectionView be responsible of showing the zoomed in cell? Or should I create a new view controller that displays the content of the cell (an image) in full screen?
I took the solution here and modified it slightly to work with a collection view instead. I also added a transparent gray background to hide the original view a bit (assuming the image doesn't take up the entire frame).
#implementation CollectionViewController
{
UIImageView *fullScreenImageView;
UIImageView *originalImageView;
}
...
// in whatever method you're using to detect the cell selection
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
originalImageView = [selectedCell imageView]; // or whatever cell element holds your image that you want to zoom
fullScreenImageView = [[UIImageView alloc] init];
[fullScreenImageView setContentMode:UIViewContentModeScaleAspectFit];
fullScreenImageView.image = [originalImageView image];
// ***********************************************************************************
// You can either use this to zoom in from the center of your cell
CGRect tempPoint = CGRectMake(originalImageView.center.x, originalImageView.center.y, 0, 0);
// OR, if you want to zoom from the tapped point...
CGRect tempPoint = CGRectMake(pointInCollectionView.x, pointInCollectionView.y, 0, 0);
// ***********************************************************************************
CGRect startingPoint = [self.view convertRect:tempPoint fromView:[self.collectionView cellForItemAtIndexPath:selectedIndexPath]];
[fullScreenImageView setFrame:startingPoint];
[fullScreenImageView setBackgroundColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.9f]];
[self.view addSubview:fullScreenImageView];
[UIView animateWithDuration:0.4
animations:^{
[fullScreenImageView setFrame:CGRectMake(0,
0,
self.view.bounds.size.width,
self.view.bounds.size.height)];
}];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(fullScreenImageViewTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[fullScreenImageView addGestureRecognizer:singleTap];
[fullScreenImageView setUserInteractionEnabled:YES];
...
- (void)fullScreenImageViewTapped:(UIGestureRecognizer *)gestureRecognizer {
CGRect point=[self.view convertRect:originalImageView.bounds fromView:originalImageView];
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];
}
-(void)animationDone:(UIView *)view
{
[fullScreenImageView removeFromSuperview];
fullScreenImageView = nil;
}
You can simply use another layout (similar to the one you already have) wherein the item size is larger, and then do setCollectionViewLayout:animated:completion: on the collectionView.
You don't need a new view controller. Your datasource remains the same. You can even use the same cell Class, just make sure that it knows when to layout things for a larger cell content size, and when not to.
I'm quite sure that's how Facebook does it in Paper, as there is no reloading of the content, i.e. [collectionView reloadData] never seems to be called (would have caused flickering and resetting of the scroll offset, etc). This seems to be the most straight forward possible solution.
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
NSLog(#"Selected cell %#", selectedIndexPath);
__weak typeof(self) weakSelf = self;
[self.collectionView setCollectionViewLayout:newLayout animated:YES completion:^{
[weakSelf.collectionView scrollToItemAtIndexPath:selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}];
You can use MWPhotoBrowser, which is suitable for your problem. It supports Grid with Tap to Zoom functionality. you can get it from here
Grid
In order to properly show the grid of thumbnails, you must ensure the property enableGrid is set to YES, and implement the following delegate method:
(id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index;
The photo browser can also start on the grid by enabling the startOnGrid property.
Related
In my app I have a UITableViewCell with a button in it.
- (void)buttonPressed:(id)sender {
UIView *test = [[UIView alloc] initWithFrame:CGRectMake(self.frame.origin.y+5, self.frame.origin.x+53, 200, 200)];
test.backgroundColor = [UIColor redColor];
test.layer.cornerRadius = 15.0f;
test.layer.masksToBounds = YES;
[self addSubview:test];
}
However, this red view is presented behind the section headers. What's the best way to add it to the view from inside the UITableViewCell in a proper way?
Get the cell you want to add it to, and then use
[cell.contentView addSubview: test];
You can get the cell from the button's frame.origin by converting the point to the table view's coordinate system and using the UITableView method indexPathForRowAtPoint. That code might looks like this:
- (NSIndexPath *) indexPathForView: (UIView*) view;
{
CGPoint viewCenter = CGPointMake(
CGRectGetMidX(view.bounds),
CGRectGetMidY(view.bounds)
);
viewCenter = [self.tableView convertPoint: viewCenter fromView: view];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: viewCenter];
return indexPath;
}
Or better yet, as an extension on UITableView:
#implementation UITableView (indexPathForCellContainingView)
- (NSIndexPath *) indexPathForCellContainingView: (UIView *) view;
{
//get the view's center point (which will be in it's parent view's coordinate system
//And convert it to the table view's coorindate system
CGPoint viewCenter = [self convertPoint: view.center fromView: view.superview];
//Ask the table view which cell's index path contains that point.
return [self indexPathForRowAtPoint: viewCenter];
}
#end
You can try this:
- (void)buttonPressed:(id)sender {
UIView *test = [[UIView alloc] initWithFrame:CGRectMake(5, 53, 200, 200)];
test.backgroundColor = [UIColor redColor];
test.layer.cornerRadius = 15.0f;
test.layer.masksToBounds = YES;
[self.contentView addSubview:test];
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewFlowLayout *myLayout=[[UICollectionViewFlowLayout alloc]init];
myLayout.scrollDirection=UICollectionViewScrollDirectionHorizontal;
[self.collectionView setCollectionViewLayout:myLayout animated:YES];
UIImageView *recipeImageView=[[UIImageView alloc]initWithFrame:CGRectMake(35, 100, 250, 250)];
recipeImageView.layer.borderColor = [UIColor redColor].CGColor;
recipeImageView.layer.borderWidth = 8.0;
[self.view addSubview:recipeImageView];
NSString *selectedRecipeImageFileName = [self.getName objectAtIndex:indexPath.row];
UIImage *selectedRecipeImage = [UIImage imageNamed:selectedRecipeImageFileName];
recipeImageView.image = selectedRecipeImage;
}
I'm using a collection view. First, I press on any image, then it will show a UIImageView on the view. If I press on another image, then again that image will appear. At this point it works properly. After that, I want to have it so if I press on a blank space then the image view hides. Please give me some ideas.
Add this to your tap gesture:
[recipeImageView removeFromSuperview];
But your image view must be accessible to any function. So you can just make a function and then call it whenever you want.
UPDATE
Sorry for delayed response. Try this:
in your .h file:
first in #interface... add <UIGestureRecognizerDelegate>
and after #interface:
#property UIImageView *recipeImageView;
in your .m files viewDidLoad:
UIGestureRecognizer *taps = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(removeImageView)];
taps.cancelsTouchesInView = NO;
taps.delegate = self;
[self.view addGestureRecognizer:taps];
and somewhere in your .m file:
-(void)removeImageView
{
[_recipeImageView removeFromSuperview];
}
Keep a pointer to that UIImageView and call removeFromSuperview on it.
Use the tap gesture on your main view to remove the UIImageView from superView.
//inside viewDidLoad initilise tap gesture
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(removeImageView:)];
tapRecognizer.numberOfTapsRequired = 1;
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewFlowLayout *myLayout=[[UICollectionViewFlowLayout alloc]init];
myLayout.scrollDirection=UICollectionViewScrollDirectionHorizontal;
[self.collectionView setCollectionViewLayout:myLayout animated:YES];
UIImageView *recipeImageView=[[UIImageView alloc]initWithFrame:CGRectMake(35, 100, 250, 250)];
recipeImageView.layer.borderColor = [UIColor redColor].CGColor;
recipeImageView.layer.borderWidth = 8.0;
// tap gesture was initialised globally.
[self.view addGestureRecognizer:tapGesture];
[self.view addSubview:recipeImageView];
NSString *selectedRecipeImageFileName = [self.getName objectAtIndex:indexPath.row];
UIImage *selectedRecipeImage = [UIImage imageNamed:selectedRecipeImageFileName];
recipeImageView.image = selectedRecipeImage;
}
Now inside the removeImageView:
- (void)removeImageView:(UITapGestureRecognizer*)sender {
UIView *view = sender.view;
//Now here check the views on which user is taping and match if user is taping on desired view where you want remove the images from superView. and also remove the tap gesture from view.
}
I am working with UICollectionView where I am displaying all the images from photo library of the phone.
When I click on any of the image, the image get flipped and and some information regarding the image is displayed.
When the user again clicks on the same image the image flips again and the original image is shown.
The problem is that whenever I scroll down through the UICollectionView the last selected image flips automatically and the information about the image gets displayed.
How to stop this problem.
Here is some code:
- (void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell1 = [collectionView cellForItemAtIndexPath:indexPath];
if(old_path!=NULL){
UICollectionViewCell *cell2 = [collectionView cellForItemAtIndexPath:old_path];
[UIView transitionFromView:cell2.selectedBackgroundView toView:cell2.contentView duration:0.5 options:UIViewAnimationOptionCurveLinear |UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
}
if(old_path==indexPath&&flag)
{
[cell1 setSelected:NO];
[UIView transitionFromView:cell1.selectedBackgroundView toView:cell1.contentView duration:0.5 options:UIViewAnimationOptionCurveLinear |UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
flag=FALSE;
}
else{
[UIView transitionFromView:cell1.contentView toView:cell1.selectedBackgroundView duration:0.5 options:UIViewAnimationOptionCurveLinear |UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
flag=TRUE;
}
old_path=indexPath;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
ALAsset *asset = assets[indexPath.row];
NSLog(#"Description : %#",[asset description]);
UIImage *img=[self imageWithImage:[UIImage imageWithCGImage:[asset thumbnail]] convertToSize:CGSizeMake(150, 150)];
UIView *contents = [[UIView alloc]initWithFrame:cell.bounds];
contents.backgroundColor = [UIColor colorWithPatternImage:img];
[cell.contentView addSubview:contents];
UIView *backgroundView = [[UIView alloc]initWithFrame:cell.bounds];
backgroundView.backgroundColor = [UIColor yellowColor];
UIButton *del=[UIButton buttonWithType:UIButtonTypeRoundedRect];
del.frame= CGRectMake(backgroundView.frame.origin.x+20, backgroundView.frame.origin.y+20, 100, 40);
[del setTitle:#"Delete" forState:UIControlStateNormal];
[del addTarget:self action:#selector(delete) forControlEvents:UIControlEventTouchUpInside];
[backgroundView addSubview:del];
UIButton *cancel=[UIButton buttonWithType:UIButtonTypeRoundedRect];
cancel.frame= CGRectMake(backgroundView.frame.origin.x+20, backgroundView.frame.origin.y+80, 100, 45);
[cancel setTitle:#"Cancel" forState:UIControlStateNormal];
[cancel addTarget:self action:#selector(cancel) forControlEvents:UIControlEventTouchUpInside];
[backgroundView addSubview:cancel];
cell.selectedBackgroundView = backgroundView;
[cell bringSubviewToFront:cell.selectedBackgroundView];
return cell;
}
Here, old_path contains the index of the last selected image.
The main problem is probably with the UIView transition methods:
[UIView transitionFromView:cell1.selectedBackgroundView toView:cell1.contentView duration:0.5 options:UIViewAnimationOptionCurveLinear |UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
UICollectionViewCell's contentView and selectedBackgroundView shouldn't be messed with like this, because the cell manages their layout. This code will remove the content view entirely and replace it with the background view, which is expected to be behind the content view when selected, and removed from the view hierarchy when not selected.
The proper way to accomplish what you're doing (showing / hiding the image in response to a tap) would be perform the transition between the image view itself and another subview on the content view.
There could also be something in your resizing code that's flipping the image, but it's hard to say without the code for imageWithImage:convertToSize:. It would probably be more efficient to get rid of that method, and do something like this:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:cell.bounds];
imageView.contentsMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
imageView.image = [UIImage imageWithCGImage:[asset thumbnail]];
[cell.contentsView addSubview:imageView];
A couple of other observations:
Collection view cells are reused, which means that your implementation collectionView:cellForItemAtIndexPath: could end up adding a whole pile of image views to a cell that has been dequeued several times. A better solution would be to subclass UICollectionViewCell and add the custom views in its init method.
The code old_path==indexPath does not actually test for equality between the two index paths, just if the two variables have the same address in memory. Use [oldPath isEqual:indexPath] instead.
You cannot do custom animations on background views without subclassing and handling explicitly. Because collection view automatically brings the selectedBackgroundView to top if selectedBackgroundView is not same as backgroundView. Adding apple documentation for reference.
// The background view is a subview behind all other views.
// If selectedBackgroundView is different than backgroundView, it will be placed above the background view and animated in on selection.
https://developer.apple.com/library/iOs/documentation/UIKit/Reference/UICollectionViewCell_class/Reference/Reference.html
I have a UIImageView within a UITableViewCell and want to expand it to fill the full screen, I have setup my UIGestureRecognizer and am using this code to expand the frame:
[UIView animateWithDuration:1.0 animations:^{
[self.ImageView setFrame:[[UIScreen mainScreen] applicationFrame]];
}];
However the UIImageView will only expand to fill the UITableViewCell and does not fill the full screen.
Any help would be much appreciated.
cells clipsToBounds is set to Yes, so view outside the cell bound will
not visible
Following method will help u to get image in cell to full Screen then get it back to same place.
You need to add gestureRecognizer to imageView and set selector as cellImageTapped
Declare UIImageView *temptumb,fullview; as instance variable.
- (void)cellImageTapped:(UIGestureRecognizer *)gestureRecognizer {
NSLog(#"%#", [gestureRecognizer view]);
//create new image
temptumb=(UIImageView *)gestureRecognizer.view;
//temptumb=thumbnail;
fullview=[[UIImageView alloc]init];
[fullview setContentMode:UIViewContentModeScaleAspectFit];
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];
}
- (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];
}
-(void)animationDone:(UIView *)view
{
[fullview removeFromSuperview];
fullview=nil;
}
UITableViewCell only expand when reloaddata or reloadRowsAtIndexPaths:withRowAnimation
otherwise it not change size in table,Simply you add UIImageView in self.view and hide image view,when tap the cell image to change image view image after hide image view when close full view
Theoretically the following code should animate the table view cell of the screen to the right and bring in a dark "view" in it's place.
CGPoint location = [gesture locationInView:tableView];
NSIndexPath *swipedIndexPath = [tableView indexPathForRowAtPoint:location];
UITableViewCell *swipedCell = [tableView cellForRowAtIndexPath:swipedIndexPath];
//code to create view
UIView *sideView;
sideView.backgroundColor = [UIColor lightGrayColor];
//set the side view frame to the same as the cell
sideView.frame = swipedCell.frame;
//add it to the tableview
[tableView addSubview:sideView];
[UIView animateWithDuration:1
animations:^{
sideView.frame = CGRectMake(0, swipedCell.frame.origin.y, swipedCell.frame.size.width, swipedCell.frame.size.height);
// While simultaneously moving the cell's frame offscreen
// The net effect is that the side swipe view is pushing the cell offscreen
swipedCell.frame = CGRectMake(swipedCell.frame.size.width, swipedCell.frame.origin.y, swipedCell.frame.size.width, swipedCell.frame.size.height); //move cell off
}];
However, only the cell moves off the screen. No gray view comes in it's place.
Is there a step I am missing? What is wrong with this code?
Video of example here
The big error is that you're not initializing sideView to anything.
Try UIView* sideview = [[UIView alloc] initWithFrame:swipedCell.frame];
It doesn't sound like a good idea to add a view in place of a cell just like that. You'd have to deal with scrolling, table view editing, and other stuff that the UITableView takes care of for you. So instead, try adding the sideView as a subview of swipedCell.contentView and then doing this animation instead:
[UIView animateWithDuration:1 animations:^{
sideView.frame = CGRectMake(0, swipedCell.frame.origin.y, swipedCell.frame.size.width, swipedCell.frame.size.height);
//This moves all the subviews except for the sideView off the screen
for (UIView *subview in swipedCell.contentView.subviews)
if (![subview isEqual:sideView])
subview.frame = CGRectOffset(subview.frame, swipedCell.frame.size.width, 0.0);
}];
Hope this helps!