UICollectionview non parallel animation - ios

My question in short: how can this effect on UICollectionView be achieved?
I have a collectionview with a custom layout that is similar to a gridlayout. Now when I enter the collectionview controller I want the cells to have a nice animation.
I know I can implement - initialLayoutAttributesForAppearingItemAtIndexPath: etc and call performBatchUpdates on the collectionview. Now when I do this all the animations are executed in parallel (like calling UIView animate). In a lot of apps I see effects where this isn't done in paralell like the philips hue app on iPhone, the effect can be seen in the movie posted at the top. One thing I could think if is that instead of inserting all the objects here the rows are added separatly, so for instance all rows are looped and dispatched after a certain interval next from each other.
Anyway if someone could hint me what the best approach is for achieving this effect or knows about a sample that does something similar I would be very grateful.

Here's one way of doing it: (I felt kinda dirty after writing this.. but it works)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.myPic.image = [UIImage imageNamed:[NSString stringWithFormat:#"%d.jpg",indexPath.row]];
CGRect frame = cell.myPic.frame;
frame.origin.y = cell.myPic.frame.origin.y + 40;
cell.myPic.frame = frame;
cell.myPic.alpha = 0;
[cells addObject:cell];
return cell;
}
- (IBAction)Run:(UIButton *)sender
{
for (int i=0; i<[cells count]; i++)
{
myCell *cell = [cells objectAtIndex:i];
[UIView animateWithDuration:0.15 animations:^() {
CGRect frame = cell.myPic.frame;
frame.size.width = 80;
frame.origin.y = cell.myPic.frame.origin.y - 40;
cell.myPic.frame = frame;
cell.myPic.alpha = 1;
}completion:^(BOOL finished){}];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
}
}

Related

What is the correct way to use UITableViewCells In Storyboard When Adding To UITableView

Hope someone can help as I've hit a bit of a roadblock. I started off with a UIScrollview that would have content with dynamic height switch in and out. After a few issues with AutoLayout I have switched to using a UITableView instead.
At the minute I have a UITableView in the main UIView and then separate UITableViewCells within storyboard. Each UITableViewCell is connected via an IBOutlet.
Now to switch the content I use the following on reloadData
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(contentToShow == 1){
UITableViewCell *cell = self.cellHome;
self.viewIcon1.layer.cornerRadius = 40;
self.viewIcon1.layer.masksToBounds = true;
self.viewIcon2.layer.cornerRadius = 40;
self.viewIcon2.layer.masksToBounds = true;
self.viewIcon3.layer.cornerRadius = 40;
self.viewIcon3.layer.masksToBounds = true;
self.viewIcon4.layer.cornerRadius = 40;
self.viewIcon4.layer.masksToBounds = true;
[self addUnderline:self.imageViewTitle];
[self addUnderline:self.imageViewTitle2];
[self addUnderline:self.imageViewTitle3];
return cell;
}else {
UITableViewCell *cell = self.cellCustInfo;
[self addUnderline:self.imageViewTitle4];
return cell;
}
}
Now this seems to change the content of the UITableView but I am having strange issues with the position of the scroll immediately after the change. I am using the following to try and get back to the top of the UITableView.
- (IBAction)showFAQScreen {
contentToShow = 2;
[UIView animateWithDuration:0.4 animations:^{
self.tableViewContent.contentOffset = CGPointZero;}];
[self.tableViewContent reloadData];
[self showMenu:nil];
}
If the scroll hasn't moved then the content is displayed correct, if it has slightly moved then the content scrolls as expected. However if the scroll has moved down significantly the scroll jumps to the bottom and it is not until I touch the scroll that it corrects itself. Any ideas what is going on and suggestions on another approach to take?
Thanks
Can you try
UIView animateWithDuration:duration animations:^{
self.tableViewContent.contentOffset = CGPointZero;
} completion:^(BOOL finished) {
[self.tableViewContent reloadData];
[self showMenu:nil];
}];

UITableviewcells unwanted animation from the side

I am trying to animate a tableview on a view that uses autolayout.
I am able to animate the tableview fine but for some reason there is a unwanted sideways animation when doing so.
The first animation closes the top tableview works fine. However the second animation that extends the bottom tableview is the one that has the sideways movement. Here is my code:
[self.dataSelectionTable layoutIfNeeded];
[self.comparatorSelectionTable layoutIfNeeded];
[UIView animateWithDuration:0.5 animations:^{
self.dataSelectionTableHeight.constant = 44;
[self.view layoutIfNeeded]; and then captures all of the frame changes
} completion:^(BOOL finished){
[UIView animateWithDuration:0.5 animations:^{
self.comparatorSelectionTableHeight.constant = 200;
[self.view layoutIfNeeded];
}];
}];
I have tried changing the animation type but that does not seem to work.
Here is a link to a gif that shows the unwanted sideways animation: http://makeagif.com/YubmP2
Edit
Here is the code for populating the tableviews:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:13.0];
}
if (tableView == self.dataSelectionTable) {
cell.textLabel.text = self.dataSelectionTitles[indexPath.row];
}
else {
cell.textLabel.text = [self.comparatorList[indexPath.row] name];
}
return cell;
}
I tried to duplicate your problem, but got slightly different results. Instead of a sideways movement, I got a downward movement of the label within the cell (but only the first time I did the animation).
I noticed that if I set the table view's height constraint's constant value to 0 in viewDidLoad, cellForRowAtIndexPath was not called until I did the expansion, so I'm guessing that some of the laying out of views of the table view wasn't happening until then.
I fixed the problem by setting the alpha value of the table view to 0 in IB, and set its height to 400 (the value I wanted after expansion). Then in viewDidAppear, I did this,
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.heightCon.constant = 0;
self.tableView.alpha = 1;
}
This caused the table's data source methods to run right away, but with the table view not visible. Now when I animated the expansion, I didn't get any movement of the label within the cell.

How to Zoom CollectionviewCell Image when it was Selected?

i make an application that conatin UICollectionview with CustumCell and each Cell Contain images i want to make when any image selected then it was zoom in view and when zoom view touch
then collectionview was Shown like as a URBMediaFocusViewController Libraray
link of library is here URBMediaFocusViewController
i know it was asked many times but please give me solution.
It's not very elegant, but this is how I do it. Basically get the frame location and size of your source UICollectionView Cell, the frame and location of where you want it to appear (in this case I fill the view), then animate between the two sizes. Hope this helps.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
[self zoomToSelectedImage:indexPath];
}
-(void)zoomToSelectedImage:(NSIndexPath *)indexPath
{
UIImageView *zoomImage = [[UIImageView alloc] initWithImage:[self.myPictures objectAtIndex:indexPath.row]];
zoomImage.contentMode = UIViewContentModeScaleAspectFit;
CGRect zoomFrameTo = CGRectMake(0,0, self.view.frame.size.width,self.view.frame.size.height);
UICollectionView *cv = (UICollectionView *)[self.view viewWithTag:66]; // Change to whatever the tag value of your collectionView is
cv.hidden = TRUE;
UICollectionViewCell *cellToZoom =(UICollectionViewCell *)[cv cellForItemAtIndexPath:indexPath];
CGRect zoomFrameFrom = cellToZoom.frame;
[self.view addSubview:zoomImage];
zoomImage.frame = zoomFrameFrom;
zoomImage.alpha = 0.2;
[UIView animateWithDuration:0.2 animations:
^{
zoomImage.frame = zoomFrameTo;
zoomImage.alpha = 1;
} completion:nil];

A UICollectionView bug with a dynamic height

Since I have been struggling for 3 days with this problem and have asked about it twice already, but maybe was not clear, I had decided to investigate the issue & found a buggy behavior with this view.
I will show the entire simple code, so anyone can reproduce the bug (iPad Air).
I am setting a collectionView flowlayout that subclasses the layout to get a constant spacing between cells, and here is the start:
TopAlignedCollectionViewFlowLayout *layout = [[TopAlignedCollectionViewFlowLayout alloc] init];
CGRect size = CGRectMake(0, 0, 900, 1200);
self.GridView = [[UICollectionView alloc] initWithFrame:size
collectionViewLayout:layout];
[self.GridView registerClass:[GridCell class] forCellWithReuseIdentifier:#"Cell"];
[self.GridView setDelegate:self];
[self.GridView setDataSource:self];
[self.view addSubview:self.GridView];
Then setting my delegates is as simple as that : (height is dynamic )
#pragma grid- main functions
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 80;
}
//cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
{
//a random dynamic height of a cell
int a = arc4random()%300;
CGSize size = CGSizeMake( 340, 240+a );
return size;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
GridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];
cell.textL.text=[NSString stringWithFormat:#"%d",indexPath.row];
NSLog(#"%d",indexPath.row);
return cell;
}
Now the subclass, to get a constant spacing : (TopAlignedCollectionViewFlowLayout)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
#define numColumns 2
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns) {
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns
inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
Anyone can check and see that after you scroll for a while, you get a strange effect of blank spaces that are filled lately by their cells,something like :
1 2
3 4
6
8
NOTE: 5-7 are loaded in later.
EDIT1:
Removing the random height from the cell size delegate method, set it to be constant height, solves this issue.
Problem is: Cell's height must be dynamic.
EDIT2:
Setting the random height (int a) to be smaller, makes also the problem to disappear,(<100), means that the smaller the distance height between cells, more likely the problem will not occur .
EDIT3 !
I have managed to set a constant distance between cells, not with subclass of the layout, but with my own memory by saving the previous cell origin and height, so i have got the constant spacing but the problem is back again ! seems that if the cells are in some certain structure, it makes the callback method that create cells, to not being called in time ! wow , i am really wondering how no one had seen this before ..
here is my implementation to create spacing with no subclassing,that also cause the problem:
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
GridCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.textL.text=[NSString stringWithFormat:#"%ld",(long)indexPath.row];
NSLog(#"%d",indexPath.row);
if(indexPath.row>1)
{
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-2 inSection:indexPath.section];
float prey=[[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"y:%ld",(long)ipPrev.row]] floatValue];
float preh=[[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"h:%ld",(long)ipPrev.row]] floatValue];
cell.frame=CGRectMake(cell.frame.origin.x, preh+prey+10, cell.frame.size.width, cell.frame.size.height);
[[NSUserDefaults standardUserDefaults] setFloat:cell.frame.origin.y forKey:[NSString stringWithFormat:#"y:%ld",(long)indexPath.row]];
[[NSUserDefaults standardUserDefaults] setFloat:cell.frame.size.height forKey:[NSString stringWithFormat:#"h:%ld",(long)indexPath.row]];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"this index:%d",indexPath.row);
NSLog(#"this cell y:%f",cell.frame.origin.y);
NSLog(#"this cell height:%f",cell.frame.size.height);
NSLog(#"previous index:%ld",(long)ipPrev.row);
NSLog(#"previous cell y: %#",[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"y:%ld",(long)ipPrev.row]]);
NSLog(#"previous cell height: %#",[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"h:%ld",(long)ipPrev.row]]);
NSLog(#"------------------------");
}
return cell;
}
Seems its a serious bug in UICollectionView, when images are bigger than screen size.
1 . UICollectionView fall back to UIScrollView
2.Large UICollectionViewCell's disappearing with custom layout
3.http://stripysock.com.au/blog/2013/3/14/working-around-a-bug-in-uicollectionview
So much work and time, for this stupid bug of apple with the reusable cells that causes nothing but headache with so many strange behaviours.
For developers who didn't have the problem i can say- just try to set dynamic height images, and iPad simulator, and you will see bugs that are just unbelievable.
So no answer for me, i will have to implement the whole thing by my self with a scrollview ,since i dont want to be depended again on things such PSTCollectionView

How to expand collectionview cell on didselect to show more info?

I want to animate my collectionview cell so that when I touch it, a mapview slides out from underneath it and basically expands into the space, by pushing the cell underneath it down a little bit. I tried using this: UICollectionView: Animate cell size change on selection, but was unable to get it to work properly.
Here what I tried.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[((FeedCell *)[collectionView cellForItemAtIndexPath:indexPath]) setIsSelected:YES];
[collectionView.collectionViewLayout invalidateLayout];
__weak FeedCell *cell = (FeedCell *)[self.photoCollectionView cellForItemAtIndexPath:indexPath]; // Avoid retain cycles
void (^animateChangeWidth)() = ^()
{
CGRect frame = cell.frame;
frame.size = CGSizeMake(frame.size.width, 420);
cell.frame = frame;
};
// Animate
[UIView transitionWithView:[collectionView cellForItemAtIndexPath:indexPath] duration:0.5f options: UIViewAnimationOptionCurveLinear animations:animateChangeWidth completion:nil];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if(((FeedCell *)[self.photoCollectionView cellForItemAtIndexPath:indexPath]).isSelected == YES){
return CGSizeMake(320, 420);
}
return CGSizeMake(320, 320);
}
I have a custom CollectionView cell and it has a property for isSelected. I'm not sure what I should do for the xib of the cell (whether to put the map view in there, have the CGSize be the selected size or deselected size, etc.) Any help would really be appreciated!
I am trying to do the same thing as you and found your question in my search. It appears that you have a pretty good solution (at least in my inexperienced opinion). What isn't working for you? I got it to do what I wanted by copying your code almost verbatim. I changed a few things, but didn't test the code before making the changes. Here is what I have that works for me in my didSelectItemAtIndexPath method:
__weak MyCell *cell = (MyCell*)[collectionView cellForItemAtIndexPath:indexPath];
[cell setSelected:YES];
[collectionView.collectionViewLayout invalidateLayout];
void (^animateChangeWidth)() = ^()
{
CGRect frame = cell.frame;
frame.size = CGSizeMake(frame.size.width, 340.0f);
cell.frame = frame;
};
// Animate
[UIView transitionWithView:cell duration:0.5f options: UIViewAnimationOptionCurveEaseInOut animations:animateChangeWidth completion:nil];
I also have overridden collectionView:layout:sizeForItemAtIndexPath so I assume that is working for you as well.
Sorry I can't be more specific. It would help if you said what about it wasn't working.

Resources