UICollectionView cell: Animation completes immediately - iphone

I've got a UICollection view that has a bunch of cells, when the user presses down on one id like to have it animate a bit. The problem i'm running into is the animation competes with no duration. Its like it just ignores the animate all together.
Heres the code from the collection view. Cells is just the collection of cells that i'm using, I tried doing cellForItemAtIndexPath: but I could'nt get the method inside the cell to call. So i created an array and put each cell inside there when they are created.
-(void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"Highlighted");
[[cells objectAtIndex:indexPath.row] shrinkCell:YES];
}
And here is the code from inside the cell.m
-(void)shrinkCell:(BOOL)shrink{
NSLog(#"Shrink");
if (shrink) {
[UIView animateWithDuration:1.0
delay:0.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
self.bg.frame = CGRectOffset(self.bg.frame, 100, 100);
}
completion:nil];
}
}
So just to reiterate. The cell does move, it just doesn't animate. Any thoughts?
Thanks!

Related

Changing the size of ScrollView not working within the tableView

So this is how my app currently looks like http://gyazo.com/f26ecd3a9d173ab76ee86946cd7a152c , when I click on More... (UIButton) the scrollView becomes slightly longer but the TableView still keeps the same size http://gyazo.com/f9f36c5b308f209d81d5a75b430eeb03 , and when I start scrolling again everything goes back to normal like the first picture showed (the scrollView goes to it's original size).
- (IBAction)moreInfo:(id)sender {
[UIView animateWithDuration:1 animations:^{
scrollView.frame = CGRectMake(0, 100, 320, 184);
}];
[sender setTitle:#"Less..." forState:UIControlStateNormal];
}
Any ideas of how I could make the scrollView become bigger and stay big even though you scroll in the tableView.
Also you need to adjust the height of cell in UITableView DataSource.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
Because you reuse the cell inside tableview

UICollectionViewCell add animation for selected/highlighted item

I'm implementing simple collection view with images inside cells. The task that I want to achieve is when user taps on the cell - there should be flip animation and some details have to appear at the same cell.
I've tried a lot of things to achieve that, for example I've added two views on the ContentView of the cell. And when user pushes the button I called transitionToView method and everything worked fine, except that when the list contained more than 9-10 images, after scrolling the list some cells started to duplicate "flipped" view with no reason. I turned off dequeueReusableCellWithReuseIdentifier function and everything worked fine, but on older devices like iPhone4, application worked to slowly.
So the best solution i found is this:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
UICollectionViewCell *cell1 = [cv dequeueReusableCellWithReuseIdentifier:kCellID3 forIndexPath:indexPath];enter code here
UIView *contents = [[UIView alloc]initWithFrame:cell1.bounds];
contents.layer.borderColor = [[UIColor colorWithRed:0.119 green:0.108 blue:0.222 alpha:1]CGColor];
contents.layer.borderWidth = 10.0f;
contents.backgroundColor = [UIColor yellowColor];
[cell1.contentView addSubview:contents];
UIView *backgroundView = [[UIView alloc]initWithFrame:cell1.bounds];
backgroundView.layer.borderColor = [[UIColor colorWithRed:0.529 green:0.808 blue:0.922 alpha:1]CGColor];
backgroundView.layer.borderWidth = 4.0f;
backgroundView.backgroundColor = [UIColor greenColor];
cell1.selectedBackgroundView = backgroundView;
[cell1 bringSubviewToFront:cell1.selectedBackgroundView];
return cell1;
}
But is it possible to add some animation for the event when cell becomes selected?
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell1 = [collectionView cellForItemAtIndexPath:indexPath];
UIView *toSwitch = cell1.contentView;
[UIView transitionFromView:toSwitch toView:cell1.selectedBackgroundView duration:0.33 options:UIViewAnimationOptionCurveLinear |UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
}
also this attempt ruins my cells - when one or more of the cells are flipped some other start to copy it..
So I need an animation (What I achieved), but I need to keep other UICollectionView cells unique and don't reuse this flipped view..
please help! :) really desperate about this!
thanks in advance
Some Solution:
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
if(cell.selected)
{
[cell setSelected:NO];
[collectionView deselectItemAtIndexPath:indexPath animated:NO];
UIView *toSwitch = cell.contentView;
[UIView transitionFromView:cell.selectedBackgroundView toView:toSwitch duration:0.001 options:UIViewAnimationOptionCurveLinear |UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
}
}
Pretty good for a temporary solution.. anyone has some better advice?
When you scroll, "old cells" are reused - that's what makes your table view perform well. Of course, if the cell in question has a transitioned view, it will show that one instead.
So, like with the data in the cell which you also set anew in each call to the cellForItemAtIndexPath function, you have to set the right view to be visible - remember the state of a cell's view like you do with data, then show the according view when the cell is presented.

Load UITableView from the bottom

I'm trying to mimic the iMessage bubble text behaviour with an UITableView. In order to always scroll to the bottom I'm using scrollToRowAtIndexPath when viewDidLoad and viewDidAppear. This is because when the viewDidLoad method is called, the table has not been completely loaded, so I need that extra scroll in viewDidAppear. This code makes the trick. However, what I want is not an animated scroll (setting animated to NO does not solve this), I want the table to be displayed always from the bottom, not load the table and then go to the last row.
Is this possible? I can't find any solution that fits completely with the desired behaviour.
This is the best solution!
Just reverse everything!
tableView.transform = CGAffineTransformMakeRotation(-M_PI);
cell.transform = CGAffineTransformMakeRotation(M_PI);
Swift 4.0:
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
Be careful though, because now the headerView and footerView positions are reversed as well.
You can avoid the call from viewDidLoad because scrolling from within viewDidAppear makes that first call redundant. viewDidAppear is called every time you navigate back to the view but viewDidLoad is only called once when the view is initialized.
I would agree with earlier suggestions of hiding the scroll from the user instead of changing the way a UITableView is loading data. My suggestion would be to use the scrollToRowAtIndexPath method in the viewWillAppear method with animation set to NO. After that if you have to add a new row while the table is visible to the user, use insertRowsAtIndexPaths:withRowAnimation: to add a row at the bottom of the table view. Be sure to take care of adding the data at the end of your data model so that when the user navigates away and comes back, s/he comes back to the same layout.
Hope this helps.
edit:
Just saw your reason for not accepting the previous answers and thought I'd elaborate a little more. The solution I propose would require minimum effort, avoid calling reloadData time and again and thus avoid calling the scrollToRowAtIndexPath method again and again. You only need to make one call to scrollToRowAtIndexPath in viewWillAppear to scroll to the bottom of the table view (hiding the transition from the user when doing so) and you wouldn't need to do that again.
I do something similar in an RPN calculator I've built. I have a table view with all the numbers in it and when a number is added to the stack, everything pops up one cell. When I load the view I call:
[self.myTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:NumOfStackItems - 1 inSection:0]
atScrollPosition:UITableViewScrollPositionTop animated:NO];
In my viewWillAppear. This way my table view starts shown at the bottom of the stack and no animation is seen. By putting this in the viewWillAppear, every time I navigate to the view, it shows up at the bottom of the table.
When I add numbers to the stack, I just add it in an array that holds all the numbers and then put the text in the proper row like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Cell initialization here...
NSUInteger row_num = [indexPath row];
cell.rowNumber.text = [NSString stringWithFormat:#"%g", [DataArray objectAtIndex:NumberOfStackItems-row_num-1];// subtract the row number off to get the correct array index
return cell
}
I also make sure that whenever I update the tableview with a new value i first call the reloadData function, and then call the scrollToRowAtIndexPath function I cited above, this way I stay at the bottom of the table.
You can have your UITableView hidden on viewDidLoad, and then change it to visible on viewDidAppear right after you scroll the table to the bottom. This way the user won't see the scrolling animation.
The solution is to override viewWillAppear and let it scroll (non-animated) to the bottom:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self goToBottom];
}
-(void)goToBottom
{
NSIndexPath *lastIndexPath = [self lastIndexPath];
[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
-(NSIndexPath *)lastIndexPath
{
NSInteger lastSectionIndex = MAX(0, [self.tableView numberOfSections] - 1);
NSInteger lastRowIndex = MAX(0, [self.tableView numberOfRowsInSection:lastSectionIndex] - 1);
return [NSIndexPath indexPathForRow:lastRowIndex inSection:lastSectionIndex];
}
By performing this at viewWillAppear it will be done before the user sees the table.
You can fix it by making an invisible footer and do the calculations in there. When the footer is loaded the contentSize is updated. To make it scroll I check set the contentOffset of the tableview.
I have commented out the animation part, since you wanted it without, but it also works.
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 1;
}
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
if( tableView.contentOffset.y != tableView.contentSize.height - tableView.frame.size.height && automaticScroll ){
//[UIView animateWithDuration:0.0 animations:^{
self.contentTableView.contentOffset = CGPointMake(0, tableView.contentSize.height - self.contentTableView.frame.size.height);
//} completion:^(BOOL finished) {
[tableView reloadData];
//}];
automaticScroll = NO;
}
UIView *emptyFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1)];
emptyFooter.backgroundColor = [UIColor clearColor];
return emptyFooter;
}
I created a BOOL automaticScroll to trigger the scroll to the bottom. This should be set in the viewWillAppear method, or whenever you load the data and reload the tableView.
If you want to add rows, you also need to set the BOOL, like:
-(void)addItemButtonClicked:(id)sender
{
automaticScroll = YES;
//Add object to data
[self.contentTableView reloadData];
}
If you need more help, please let me know.
scrollToRowAtIndexPath
use to scroll the row in tableview to particular position
just change content inset after load data to move content view of table view if height is less than parent view.
[self.tableView reloadData];
[self.tableView setContentInset:UIEdgeInsetsMake(self.view.frame.size.height - self.tableView.contentSize.height < 0 ? 0 : self.view.frame.size.height - self.tableView.contentSize.height, 0, 0, 0)];
Swift 3.1
tableView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
Credits: #Christos Hadjikyriacou

UITableViewCell animation when scrolling

I've implemented Cocoa with Love's example for Multi-row selection which involves creating a custom UITableViewCell that initiates an animation in layoutSubviews to display checkboxes to the left of each row, like so:
- (void)layoutSubviews
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[super layoutSubviews];
if (((UITableView *)self.superview).isEditing)
{
CGRect contentFrame = self.contentView.frame;
contentFrame.origin.x = EDITING_HORIZONTAL_OFFSET;
self.contentView.frame = contentFrame;
}
else
{
CGRect contentFrame = self.contentView.frame;
contentFrame.origin.x = 0;
self.contentView.frame = contentFrame;
}
[UIView commitAnimations];
}
This works fine and for all intents and purposes my UITableView acts as it should. However I'm running into a small aesthetic issue: when scrolling my UITableView rows which have not previously been displayed will initiate their sliding animation, meaning the animation is staggered for certain rows as they come into view.
This is understandable, given that setAnimationBeginsFromCurrentState has been set to YES and rows further down in the UITableView have yet to have their frame position updated. To solve the issue, I attempted to use willDisplayCell to override the animation for cells which become visible while the UITableView is in edit mode. Essentially bypassing the animation and updating the rows frame immediately, so as to make it appear as if the cell has already animated into place, like so:
/*
Since we animate the editing transitions, we need to ensure that all animations are cancelled
when a cell is scheduled to appear, so that things happen instantly.
*/
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell.contentView.layer removeAllAnimations];
if(tableView.isEditing) {
CGRect contentFrame = cell.contentView.frame;
contentFrame.origin.x = EDITING_HORIZONTAL_OFFSET;
cell.contentView.frame = contentFrame;
} else {
CGRect contentFrame = cell.contentView.frame;
contentFrame.origin.x = 0;
cell.contentView.frame = contentFrame;
}
}
Unfortunately this doesn't seem to have any effect. Does anyone have any idea as to how I can solve this issue?
Not sure if you still need an answer to this question but I just ran into the exact same issue so I thought that I would share my solution. I implemented Multi-Selection the same way its described in the Cocoa with Love blog post that you mentioned.
In the cellAtIndexPath DataSource method when I create a new cell (not if the cell is already in the Queue of reusable cells) I check if the tableView is in editing mode and if it is I set a property on the cell (I created my own custom cell with an EnableAnimation property) to false so when it gets the SetEditing callback it will not animate the cell, instead it will just set the frame. In the constructor of the Cell class I set EnableAnimation to true, when the SetEditing callback is called I set EnableAnimation to the animate argument that is passed in. I hope this helps.

Animate removal of UITableViewCellAccessory

Is there any way to animate the removal of a UITableView cell accessory?
I currently am showing a UITableViewCellAccessoryDisclosureIndicator, but I would like to animate swapping the disclosure indicator with a UISwitch on all visible table cells.
I've tried something like this:
[UIView animateWithDuration:0.3
animations:^{
for (SwitchTableViewCell *cell in self.tableView.visibleCells)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}];
... but unfortunately that has no affect. The disclosure indicator abruptly disappears and the contentView width jumps in one step, rather than a smooth transition.
accessoryType is not an animatable property. There are two ways you can do this, depending on your situation. The easiest only applies if you are changing the accessory to a UISwitch because of entering the editing state. In this case, just usecell.editingAccessoryType = theSwitch; in your tableView:cellForRowAtIndexPath: method. The table view will then do a fade in/out automatically when entering editing mode.
If you are doing this outside of editing mode, then the following code will do what you want:
[UIView animateWithDuration:0.3 animations:^{
for(SwitchTableViewCell *cell in self.tableView.visibleCells) {
[[cell valueForKey:#"_accessoryView"] setAlpha:0.0];
}
} completion:^(BOOL done) {
for(SwitchTableViewCell *cell in self.tableView.visibleCells) {
cell.accessoryView = theSwitch;
}
}];
However, I do not know if this code will make it into the app store since it uses the hidden property _accessoryView.