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
Related
- (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.
}
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.
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
Please help. Trying to get animation of frame position working inside a UITableViewCell, specifically I'm trying to move the default UILabel (cell.textLabel). However, no matter what technique I use, I can't get any view inside the cell to move. The animation of colour and alpha works as outlined by the code below.
Cheers in advance for help.
Andy
Here is the code I am using:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 0) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
CGRect textLabelFrame = cell.textLabel.frame;
textLabelFrame.origin.x = -textLabelFrame.size.width;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
cell.textLabel.frame = textLabelFrame; // THIS DOESN'T WORK - HELP!
cell.imageView.frame = CGRectOffset(cell.imageView.frame,0,0); // EVEN TRYING TO MOVE IMAGEVIEW DOESN'T WORK
cell.textLabel.alpha = 0; // This animates
cell.imageView.backgroundColor = [UIColor redColor]; // This animates
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
}
I don't think it's possible to reposition the default label or image view in a standard cell. If you want to do that, you should add your own subviews to the cell's contentView, and do your animations with those.
My application has splitview and it's activated only in landscape mode.
In masterview i have tableview and in the last section i have a custom button.
The problem is that the button width stays in potrait instead of using device orientation.
I've tried to play with setAutoresizingMask on button and view but that doesn't work either.
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) sectionNum {
if (sectionNum == 4) {
CGRect frameSize;
if (UIInterfaceOrientationIsLandscape([[UIDevice currentDevice] orientation])) {
frameSize = CGRectMake(45.0, 0.0, 600.0, 44.0);
} else {
frameSize = CGRectMake(45.0, 0.0, 680.0, 44.0);
}
UIView *btnView = [[[UIView alloc] initWithFrame:frameSize] autorelease];
// button
UIButton* btnFind = [UIButton buttonWithType:UIButtonTypeCustom];
[btnFind setBackgroundImage:[[UIImage imageNamed:#"buttonblue.png"] stretchableImageWithLeftCapWidth:14.0 topCapHeight:0.0] forState:UIControlStateNormal];
[btnFind setBackgroundImage:[[UIImage imageNamed:#"buttonred.png"] stretchableImageWithLeftCapWidth:14.0 topCapHeight:0.0] forState:UIControlStateHighlighted];
btnFind.frame = frameSize;
btnFind.tag = 1;
[btnFind setTitle:#"Find" forState:UIControlStateNormal];
[btnFind addTarget:self action:#selector(doSearchDoc:) forControlEvents:UIControlEventTouchUpInside];
//[btnFind setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
//[btnView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[btnView addSubview:btnFind];
return btnView;
}
return nil;
}
Can someone please let me know how to resolve this.
Thanks.
I've had other issues that the header was not refreshed when rotating the device, ie. the method above was not invoked in my situatio, you could check if this is the case also for you.
The solution I adopted was to invoke reloadData in the rotating method :
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// This solves an issue that the header doesn't show when roating device (ok on simulator)
NSIndexPath* ipselected = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:ipselected animated:false scrollPosition:UITableViewScrollPositionMiddle];
}
Of course it is usable if you can afford a full reload when rotating the device but itis typically a time when the user will better accept a 0.5s delay as he/she is busy with moving the device.
lternatively you could keep an ivar to your button and change its frame in the above method.