I have a UIImageView that currently moves to whichever row in a UITableView is selected by the user. This functionality is working fine. However, what I want to do now is also control its movement by using a button. I have two buttons, one for going up one row, and one for going down one row. Both buttons have different tag values but call the same IBAction method. What I want to know is how do I move the UIImageView up/down by one row? I presently have the following code which works fine:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.view bringSubviewToFront:_imageView];
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[tableView rectForRowAtIndexPath:indexPath] fromView:tableView];
_imageView.frame = rect;
}];
}
The above method works fine in moving the UIImageView to whichever row the user has selected.
How do I modify this code so that it strictly moves up exactly one row each time the up button is pressed, and down exactly one row each time the down button is pressed?
Get the table view cell's indexPath from the last selected row in didSelectRowAtIndexPath: method in a NSIndexPath object.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.view bringSubviewToFront:_imageView];
self.indexPath = indexPath;
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[tableView rectForRowAtIndexPath:indexPath] fromView:tableView];
_imageView.frame = rect;
}];
}
Process the indexPath in your button action method to see if the above/below cell will be in same section,in which case increment/decrement the row and if in other section, you might want to calcuate new indexPath.
-(IBAction)btnActn:(id)sender{
if(btn.tag ==0){
self.indexPath=[NSIndexPath indexPathForRow:self.indexPath.row+1 inSection:self.indexPath.section];
//Put animation code or call animation function
}
}
And then get the rect of one cell above or below's frame using the same method you already are using and translate the _imageView's location to the new location.
Related
I have a view with 11 rows which contains textfields, textViews
Total height of all the elements > ScreenHeight
I have a textfield as the second last element.
Empty row as the last element
To present this View, I used TableView
I use different identifier for different types of elements.
In CellForRowAtIndexPath, I return cell based on indexaPath.row
The view is displayed as expected.
I scroll and still rows are displayed as expected
Since Textfield is at the end and keyboard is presented, so
When textField is clicked
I move the tableView.frame up by keyboard.height
It moves up correctly.
I see cellForIndexPath called for last element (indexPath.row = 10)
Now the problem starts
textField.cell.row = 9 (10th Element)
To dismiss keyboard, I press on the cell below the "textFieldCell" (last element) which is expected to be a row with indexPath.row = 10
In textField.didEndEditing, I reset tableView.frame = originalFrame
I scrollToBottomAnimated
Now I see, iOS calling cellForIndexPath = 7,6,5,4
But didSelectRowAtIndexPath gives me the rowNumber = 7 which is not what I clicked.
I clicked row 11th or indexPath.row = 10
But due to resizing of tableView and scolling, things went wrong.
What am I doing wrong.
What do I need to do to get indexPath.row = 10 and not 7 when I click the last cell?
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[UIView beginAnimations:#"moveView" context:nil];
[UIView setAnimationDuration:0.0];
self.frame=CGRectMake(0,66,ScreenWidth,ScreenHeight - keyboardFrame.size.height-66);
[UIView commitAnimations];
[self scrollToBottomRowAnimated:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
[UIView beginAnimations:#"moveView" context:nil];
[UIView setAnimationDuration:0.0];
self.frame=CGRectMake(0,66,ScreenWidth,ScreenHeight - 66);
[UIView commitAnimations];
[self scrollToBottomRowAnimated:YES];
}
- (void)scrollToBottomRowAnimated:(BOOL)animated
{
long lastRowNumber = [self numberOfRowsInSection:0]-1;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
[self scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom animated:animated];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(indexPath.row);
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
}
I suspect (not sure though) the problem is you are mixing two types of animations really and in the approach to shrinking the table view to compensate for keyboard.
Do not use tableview frame change via committed animations. Instead I recommend using a trivial vertical content offset in the table view. UITableView is really a UIScrollView subclass, so it has all the methods for scrollview and it supports vertical content offset for its content.
In textfieldDidBeginEditing:
[self.tableView setContentOffset:CGPointMake(0, kKeyboardHeight) animated:YES];
and in textfieldDidEndEditing just get rid of the offset via
[self.tableView setContentOffset:CGPointZero animated:YES];
I have a UITableView displaying cells. I am using Auto Layout. At some point, I add cells to a section of my tableView and I need to animate a subview of each cells as soon as the cells are visible.
I wrote the following method to animate the content of my cell:
- (void)animateWithPercentage:(NSNumber *)percentage
{
self.progressViewWidthConstraint.constant = [percentage intValue];
[self.progressView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.6f animations:^{
[self.progressView layoutIfNeeded];
}];
}
The method works as expected but I don't know when to call it.
If I call it when - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath is called, I end up animating the whole layout of my cell because the cell did not layout itself before.
I also tried calling it in layoutSubviews but the animation is skipped. I guess at this point it is too early to animate anything.
Any idea where my method should be called?
I've gotten this kind of animation to work by calling performSelector:withObject:afterDelay: in either awakeFromNib or didMoveToSuperview in the custom cell's class. It works even with a delay of 0, but it doesn't work if you just use performSelector. I've noticed that with this method, if some of the cells are off screen, they don't update until they are scrolled on, and the scrolling animation ends. You can get the animation to start as soon as the cell scrolls on screen, even while the scrolling animation is still in progress by using dispatch_async instead.
-(void)awakeFromNib {
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:2 animations:^{
self.rightCon.constant = 150;
[self.contentView layoutIfNeeded];
} completion:nil];
});
}
Try to put your method in -(void)didMoveToSuperview
I've got an UITableView in which I display a list of stuff, on the right side of cell there is an UIView (called viewFlipContainer) which contains of two other views (viewPicture with UIImageView and viewPlayer with EVCircularProgressView). When user taps picture I use this code to flip it to progress view:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:viewFlipContainer cache:NO];
viewPicture.hidden = YES;
viewPlayer.hidden = NO;
[UIView commitAnimations];
And when user taps to stop playback I use the same code (but with switched hidden properties and UIViewAnimationTransitionFlipFromRight) to "unflip" views. When other cell is playing and user taps another one, the first one is unflipped.
Everything works as a charm, but there's a nasty little problem I've been fighting almost a week now.
For example I've 20 rows on my list. If I tap on image #1, then scroll the list to hide it offscreen, then tap on #12 (and while it is buffering audio, and only then) tap on something other on screen, like #13 during "unflip" animation image on #12 shows some random image (I think it is the picture from cell that went offscreen last). When the animation ends the picture goes back to the one it should be. While all tapped images are on screen then it all works as intended.
This puzzles me because the image is correct before and after animation, but it is different while animating. I'm using reloadData only when changing all data source, and I'm using reloadRowsAtIndexPaths to update playback progress on the cell that is "playing" right now.
If there is something else that could be useful and I've omitted it please let me know, I'll try to update it, but not everything I could share (it's an commercial app that I'm working on).
Edit #1
That's how I'm loading cells into UITableView:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TVCCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[TVCCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
NSDictionary *row = [stuffToDisplay objectAtIndex:indexPath.row];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userStoppedPlayback:)];
[cell.viewPlayer addGestureRecognizer:tap];
cell.tag = [[row objectForKey:#"id"] integerValue];
[cell setDataForCellFromDictionary:row];
return cell;
}
setDataForCellFromDictionary it's just a method which sets up all UILabels and UIImages according to data in dictionary
I am trying to create a UITableView that has a selection bar that scrolls to whichever row the user has selected (please don't ask why, I just have to do this). This is different from the typical selection bar that the UITableView has, because there is no animation there. What I've done is added a TableView in Interface Builder to my main view, and I've also added an imageView to my main view. I need this to work similar to the selection bar in the UIPickerView except that in this case it is the selection bar that moves. I figure the code for this would reside inside:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CGRect rect = [tableView rectForRowAtIndexPath:indexPath];
_imageView.frame = rect;
}
Can anyone explain to me how I would code the animation of the selection bar from cell to cell?
Thanks in advance to all who reply
Assuming the code you currently have works:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [tableView rectForRowAtIndexPath:indexPath];
_imageView.frame = rect;
}];
}
There is also +animateWithDuration:animations:completion: and +animateWithDuration:delay:options:animations:completion:
I have a UIImageView that is supposed to cover the selected row from a UITableView. Both, the UIImageView, and UITableView are added to the main View inside Interface Builder. Instead of covering up the cell when it is selected, the UIImageView moves to the selected cell and disappears behind it. What I need it to do is move up to the selected row, and cover it up (i.e. the image should be in front of the cell, not behind it). Please also bear in mind that my image needs to only cover the selected row. Here is my relevant code:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[UIView animateWithDuration:.3 animations:^{
//CGRect rect = [tableView rectForRowAtIndexPath:indexPath];
CGRect rect = [self.view convertRect:[tableView rectForRowAtIndexPath:indexPath] fromView:tableView];
_imageView.frame = rect;
}];
}
Can anyone see what I am doing wrong, and know how to fix this?
Thanks in advance to all who reply.
It is simply because the imageView is added before the table view in the subviews, I guess. Hence you can use bringSubviewToFront method and apply it to the imageView after you add your tableView to the subviews, for example.