TableView scrolls to middle when a new row is inserted - ios

I have a table view that displays messages that I fetch from over the network.
When a new message comes in, it should be added to the tableview at the bottom.
When a new messages comes in, it is added to the bottom of the tableview properly, but the tableview then immediately scrolls to the middle. (So if I had say 100 cells in there now, cell 50 would be in the middle of the scroll view now).
The weird thing is that this only happens if the scroll point before the insert is in the lower half of the tableview.
So, if I'm looking at cell 10 of 99, and I add a row, it gets added to the bottom just fine.
But, if I'm looking at cell 75 of 99, and I add a row, the scroll position jumps up to the middle (~cell 50) again.
Here's my code for adding a new message to the tableview:
[self.tableView beginUpdates];
[self.messages addObject:message];
NSArray *indexPaths = #[[NSIndexPath indexPathForRow:(self.messages.count - 1) inSection:0]];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
Why is the tableview scrolling automatically like this?

I too have this problem.
NSTableView and UITableView are probably similar... their default scrolling behavior both SUCK.
TableView is not designed to be used as a spreadsheet style editor,
so over the years I've added thousands of lines of code to make it
work sort of like a spreadsheet.
I wish Apple would just create a NSSpreadsheetView subclass of NSTableView to fix all this stuff:
- cursor keys navigate cells
- sensible scroll behavior
- add hoc cell selection
Would also like to see a NSLogView subclass of NSTableView which behaves like Console.app, with a search field.
My solution was to add several category methods:
#implementation NSTableView (VNSTableViewCategory)
-(NSInteger)visibleRow
{
NSRect theRect = [self visibleRect];
NSRange theRange = [self rowsInRect:theRect];
if ( theRange.length == 0 )
return -1;
else if ( NSLocationInRange( [self editedRow], theRange ) )
return [self editedRow];
else if ( NSLocationInRange( [self clickedRow], theRange ) )
return [self clickedRow];
else if ( NSLocationInRange( [self selectedRow], theRange ) )
return [self selectedRow];
else
return theRange.location + (theRange.length/2);
}
-(NSRange)visibleRows
{
NSRect theRect = [self visibleRect];
NSRange theRange = [self rowsInRect:theRect];
return theRange;
}
-(void)scrollRowToVisibleTwoThirds:(NSInteger)row
{
NSRect theVisRect = [self visibleRect];
NSUInteger numRows = [self numberOfRows];
NSRange visibleRows = [self rowsInRect:theVisRect];
//NSUInteger lastVisibleRow = NSMaxRange(visibleRows);
if ( NSLocationInRange( row, visibleRows ) )
{
if ( row - visibleRows.location < (visibleRows.length * 2 / 3) )
{
// may need to scroll up
if ( visibleRows.location == 0 )
[self scrollRowToVisible:0];
else if ((row - visibleRows.location) > 2 )
return;
}
}
NSRect theRowRect = [self rectOfRow:row];
NSPoint thePoint = theRowRect.origin;
thePoint.y -= theVisRect.size.height / 4; // scroll to 25% from top
if (thePoint.y < 0 )
thePoint.y = 0;
NSRect theLastRowRect = [self rectOfRow:numRows-1];
if ( thePoint.y + theVisRect.size.height > NSMaxY(theLastRowRect) )
[self scrollRowToVisible:numRows-1];
else
{
[self scrollPoint:thePoint]; // seems to be the 'preferred' method of doing this
// kpk note: these other approaches cause redraw artifacts in many situations:
// NSClipView *clipView = [[self enclosingScrollView] contentView];
// [clipView scrollToPoint:[clipView constrainScrollPoint:thePoint]];
// [[self enclosingScrollView] reflectScrolledClipView:clipView];
// [self scrollRowToVisible:row];
// [[[self enclosingScrollView] contentView] scrollToPoint:thePoint];
// [[self enclosingScrollView] reflectScrolledClipView:[[self enclosingScrollView] contentView]];
}
}
#end // NSTableView (VNSTableViewCategory)
Usage Example:
NSRange visRows = [toScenesTable visibleRows];
visRows.length -= 2;
if ( iAlwaysScroll == YES || !NSLocationInRange(row, visRows) )
{
[toScenesTable scrollRowToVisibleTwoThirds:row]; // VNSTableViewCategory
}

I think you need to change the row animation to none-
[self.tableView
insertRowsAtIndexPaths:indexPaths
withRowAnimation:
UITableViewRowAnimationNone];

Try this
[self.tableView scrollToRowAtIndexPath:indexpath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
also you can change the position to middile,top or none.

Related

Header view not getting re-arranged after scrolling in UICollectionView

I have a UICollectionView which expands on clicking a cell and once the screen fills it becomes scrollable.
Now when I scroll down I need my header view to scroll down with it and for that I've implemented the logic in the layoutAttributesForSupplementaryViewOfKind method in my custom UICollectionViewLayout class.
This works fine but now the issue is that when I the content becomes scrollable and I scroll down few cells and immediately click on a cell to shrink the content back to one screen at that point the header view doesn't gets arranged, i.e it still remains in the last scrolled position.
But there after if I perform any other action like cell tap it gets arranged properly.
I've tried calling setNeedsLayout, setNeedsDisplay and layoutSubviews where I reload my UICollectionView but the header still doesn't updates to its proper position.
Below is the code for my layoutAttributesForSupplementaryViewOfKind method.
Any help is appreciated.
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
if (![kind isEqualToString:[myGridHeaderView kind]]) {
return nil;
}
myGridHeaderPosition headerPosition = [[self collectionView] headerPositionAtIndexPath:indexPath];
CGRect cellRect = [[self delegate] getRectForHeaderAtIndex:indexPath headerPosition:headerPosition];
if (CGRectEqualToRect(cellRect, CGRectZero)) {
return nil;
}
myGridHeaderLayoutAttribute* attributes = [myGridHeaderLayoutAttribute layoutAttributesForSupplementaryViewOfKind:kind withIndexPath:indexPath];
CGPoint centerPoint = CGPointMake(CGRectGetMidX(cellRect), CGRectGetMidY(cellRect));
CGSize size = cellRect.size;
UICollectionView * const cv = self.collectionView;
NSInteger zIndex = 1;
CGPoint const contentOffset = cv.contentOffset;
if (contentOffset.x > 0)
{
if (headerPosition != myGridHeaderPositionColumn)
{
centerPoint.x += contentOffset.x;
}
zIndex = 1005;
}
if (contentOffset.y > 0)
{
if (headerPosition != myGridHeaderPositionRow)
{
centerPoint.y += contentOffset.y;
}
zIndex = 1005;
}
if (headerPosition == myGridHeaderPositionCommon) {
zIndex = 1024;
}
attributes.zIndex = zIndex;
attributes.headerPosition = headerPosition;
attributes.center = centerPoint;
attributes.size = size;
attributes.alpha = 1.0;
return attributes;
}
When you scroll up and down , header will be visible and hidden , for use this code.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
isScrollingStart=YES;
NSLog(#"scrollViewDidScroll %f , %f",scrollView.contentOffset.x,scrollView.contentOffset.y);
if (scrollView.contentOffset.y<=124) {
_img_top_header.alpha=scrollView.contentOffset.y/124;
}
else
{
_img_top_header.alpha=1.0;
}
}
must be set image in header.

Only one sticky header in UICollectionView

I'm trying to implement a single sticky header in a UICollectionView.
My sticky header behavior is a bit different than the usual one you can see e.g. in UITableView. I have 3 headers in the collection view and I want only one of them to be sticky and stick to the top when the content is scrolled.
My code works pretty well. However, when I scroll down, the sticky header disappears suddenly at some point. Scrolling back makes the header appear again. What am I doing wrong?
I am attaching a implementation of my custom layout. It's a subclass of UICollectionViewFlowLayout.
#implementation CustomFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *attributes = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
CGPoint const contentOffset = self.collectionView.contentOffset;
for (UICollectionViewLayoutAttributes *layoutAttributes in attributes)
{
// Adjust the sticky header frame.
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader] &&
layoutAttributes.indexPath.section == SectionWithStickyHeadeIndex)
{
NSInteger numberOfItemsInSection = [self.collectionView numberOfItemsInSection:SectionWithStickyHeadeIndex];
NSIndexPath *firstObjectIndexPath = [NSIndexPath indexPathForItem:0
inSection:SectionWithStickyHeadeIndex];
UICollectionViewLayoutAttributes *firstObjectAttrs;
if (numberOfItemsInSection > 0)
{
firstObjectAttrs = [self layoutAttributesForItemAtIndexPath:firstObjectIndexPath];
}
else
{
firstObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
atIndexPath:firstObjectIndexPath];
}
CGPoint origin = layoutAttributes.frame.origin;
// Adjust the header origin so it sticks to the top.
origin.y = MAX(contentOffset.y + self.collectionView.contentInset.top,
CGRectGetMinY(firstObjectAttrs.frame) - CGRectGetHeight(layoutAttributes.frame));
layoutAttributes.zIndex = CGFLOAT_MAX;
layoutAttributes.frame = (CGRect)
{
.origin = origin,
.size = layoutAttributes.frame.size
};
break;
}
}
return attributes;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBound
{
return YES;
}
#end
I'm not 100% sure on this, but it looks like once you scrolled down far enough, the header's original position was no longer located inside the rect argument. This caused the header's layout attributes to not be included in the attributes array you iterated over in in the for loop, resulting in the layout position no longer being adjusted to its "sticky" position at the top of the screen.
Try adding these lines right before the for loop to add the sticky header's layout attributes to the attributes array if they are not already there:
NSIndexPath *stickyHeaderIndexPath = [NSIndexPath indexPathForItem:0 inSection:SectionWithStickyHeaderIndex];
UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
atIndexPath:stickyHeaderIndexPath];
if (![attributes containsObject:layoutAttributes])
{
[attributes addObject:layoutAttributes];
}
The answer in Swift 5
let headerIndexPath = IndexPath(item: 0, section: 0)
if let headerAttributes = layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: headerIndexPath) {
if !attributes.contains(headerAttributes) {
attributes.append(headerAttributes)
}
}
All thanks to #BrendanCain

Creating a stack of photos with UICollectionView which a user can swipe through

I am attempting to create a stack of photos using UICollectionView in which a user can swipe a photo to the side. As a photo is dragged, it gets smaller (to a minimum scale) and the photo behind is enlarged to a maximum scale. This maximum scale is the original size of the foreground photo.
When the pan gesture which drags the foreground photo ends, if it is the minimum scale, it is sent to the back of the stack, otherwise, it is animated back to the centre of the screen and enlarged back to its original size (along with the growing photo behind it).
I hope you're still with me haha.
Now, assuming the photo being dragged is at its minimum size, I remove user interaction of the UICollectionView, animate the photo to the centre of the screen again, and its size is animated to match the rest of the background images. I then send the cell to the back of the UICollectionViews subviews.
Once all of these animations have taken place, I update my data source (an array of images) by adding the photo in front to the back, then deleting that photo at the front.
Then, I update the UICollectionView. This consists of a batch update in which I delete the item at an NSIndexPath of 0 : 0, then, insert an item at NSIndexPath ([photo count] - 1) : 0.
When this batch update finished, I reload my UICollectionView (as only the item at NSIndexPath 0 : 0 has a pan gesture) and re-add user interaction to the UICollectionView.
I hope this makes sense.
Notes
The size of the background photos is a percent of 80%.
The size of the foreground photo is a percent of 100%.
This is relative to the UICollectionView which fits the screen of the iPhone.
My problem
My code seems to work very well. My issue comes from when I take my finger off the screen (the pan gesture ends) and the animation of the photo (centring it to the centre of the screen and sizing it like the rest of the background photos) ends.
The photo dragged off reappears on screen, sizes from the size of the background photos (80%) to the size of the foreground photo (100%) then fades away. Once this happens the photos are reordered as expected.
Does anyone know why this might happen?
Here is my Pan Gesture code:
CGPoint touchTranslation = [gesture translationInView:self.view];
static CGPoint originalCenter;
DIGalleryCollectionViewLayout *galleryCollectionViewLayout = (DIGalleryCollectionViewLayout *)self.galleryCollectionView.collectionViewLayout;
if (gesture.state == UIGestureRecognizerStateBegan) {
//
// Began.
//
originalCenter = gesture.view.center;
} else if (gesture.state == UIGestureRecognizerStateChanged) {
//
// Changed.
//
CGPoint translate = [gesture translationInView:gesture.view.superview];
touchTranslation = CGPointMake(originalCenter.x + translate.x, originalCenter.y + translate.y);
[gesture.view setCenter:touchTranslation];
CGPoint pointsPhotoIsMovedBy = CGPointMake(fabsf(fabsf(originalCenter.x) - fabsf(touchTranslation.x)),
fabsf(fabsf(originalCenter.y) - fabsf(touchTranslation.y)));
// Update cells.
//
CGFloat currentIncrement = MAX(pointsPhotoIsMovedBy.x, pointsPhotoIsMovedBy.y);
for (NSIndexPath *indexPath in self.galleryCollectionView.indexPathsForVisibleItems) {
UICollectionViewCell *cell = [self.galleryCollectionView cellForItemAtIndexPath:indexPath];
if ([indexPath isEqual:[NSIndexPath indexPathForItem:0 inSection:0]]) {
//
// Front.
//
CGFloat frontScalePercent = MIN(GalleryCollectionViewLayoutFrontRatioDefault,
MAX(GalleryViewFrontScaleMinimum, GalleryCollectionViewLayoutFrontRatioDefault - (currentIncrement / 250.0f)));
[cell setTransform:CGAffineTransformMakeScale(frontScalePercent, frontScalePercent)];
} else if ([indexPath isEqual:[NSIndexPath indexPathForItem:1 inSection:0]]) {
//
// Next.
//
CGFloat nextScalePercent = MAX(GalleryCollectionViewLayoutBackRatioDefault,
MIN(GalleryViewNextScaleMaximum, (currentIncrement / 150.0f)));
[cell setTransform:CGAffineTransformMakeScale(nextScalePercent, nextScalePercent)];
} else {
//
// Background.
//
[cell setTransform:CGAffineTransformMakeScale(GalleryCollectionViewLayoutBackRatioDefault,
GalleryCollectionViewLayoutBackRatioDefault)];
}
}
} else if (gesture.state == UIGestureRecognizerStateEnded) {
//
// Ended.
//
if (gesture.view.transform.a == GalleryViewFrontScaleMinimum) {
//
// Next photo.
//
[self.galleryCollectionView setUserInteractionEnabled:NO];
[self.galleryCollectionView sendSubviewToBack:gesture.view];
[UIView animateWithDuration:0.3f
animations:^{
[gesture.view setCenter:self.galleryCollectionView.center];
[gesture.view setTransform:CGAffineTransformMakeScale(GalleryCollectionViewLayoutBackRatioDefault,
GalleryCollectionViewLayoutBackRatioDefault)];
}
completion:^(BOOL finished) {
//
// Data source
//
NSMutableArray *photos = [self.photos mutableCopy];
[photos addObject:[photos objectAtIndex:0]];
[photos removeObjectAtIndex:0];
[self setPhotos:photos];
// Contents
//
[self.galleryCollectionView performBatchUpdates:^{
[self.galleryCollectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]]];
[self.galleryCollectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:(self.photos.count - 1) inSection:0]]];
} completion:^(BOOL finished) {
[self.galleryCollectionView reloadData];
[self.galleryCollectionView setUserInteractionEnabled:YES];
}];
}];
} else {
//
// Stay.
//
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionCurveEaseIn
animations:^{
//
// Front cell.
//
[gesture.view setCenter:self.galleryCollectionView.center];
[gesture.view setTransform:CGAffineTransformMakeScale(GalleryCollectionViewLayoutFrontRatioDefault,
GalleryCollectionViewLayoutFrontRatioDefault)];
// Next cell.
//
for (NSIndexPath *indexPath in self.galleryCollectionView.indexPathsForVisibleItems) {
if ([indexPath isEqual:[NSIndexPath indexPathForItem:1 inSection:0]]) {
//
// Next.
//
UICollectionViewCell *cell = [self.galleryCollectionView cellForItemAtIndexPath:indexPath];
[cell setTransform:CGAffineTransformMakeScale(GalleryCollectionViewLayoutBackRatioDefault,
GalleryCollectionViewLayoutBackRatioDefault)];
}
}
}
completion:^(BOOL finished) {
[galleryCollectionViewLayout setFrontRatio:GalleryCollectionViewLayoutFrontRatioDefault];
[galleryCollectionViewLayout setNextRatio:GalleryCollectionViewLayoutBackRatioDefault];
[galleryCollectionViewLayout invalidateLayout];
}];
}
}
And here is my prepareLayout: code for the collection view layout:
NSMutableDictionary *newLayoutInfo = [NSMutableDictionary dictionary];
NSMutableDictionary *cellLayoutInfo = [NSMutableDictionary dictionary];
NSIndexPath *indexPath;
for (NSInteger section = 0; section < [self.collectionView numberOfSections]; section++) {
NSInteger itemCount = [self.collectionView numberOfItemsInSection:section];
for (NSInteger item = 0; item < itemCount; item++) {
indexPath = [NSIndexPath indexPathForItem:item inSection:section];
UICollectionViewLayoutAttributes *itemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
[itemAttributes setSize:[self sizeForPhotoAtIndexPath:indexPath inContainerOfSize:self.collectionView.bounds.size]];
[itemAttributes setCenter:self.collectionView.center];
// Z Index.
//
NSInteger zIndex = itemCount - item;
[itemAttributes setZIndex:zIndex];
// Scale cells based on z position.
//
if (zIndex == itemCount) {
//
// Foreground.
//
[itemAttributes setTransform:CGAffineTransformMakeScale(self.frontRatio, self.frontRatio)];
} else if (zIndex == itemCount - 1) {
//
// Next.
//
[itemAttributes setTransform:CGAffineTransformMakeScale(self.nextRatio, self.nextRatio)];
} else {
//
// Background.
//
[itemAttributes setTransform:CGAffineTransformMakeScale(GalleryCollectionViewLayoutBackRatioDefault,
GalleryCollectionViewLayoutBackRatioDefault)];
}
cellLayoutInfo[indexPath] = itemAttributes;
}
}
newLayoutInfo[GalleryCollectionViewLayoutCellKind] = cellLayoutInfo;
self.layoutInfo = newLayoutInfo;
And as an additional reference, here is my code for sizeForPhotoAtIndexPath: inContainerOfSize:
UIImage *photo = [[(DIGalleryViewController *)self.collectionView.delegate photos] objectAtIndex:indexPath.row];
CGSize size = CGSizeMake(photo.size.width, photo.size.height);
UIGraphicsBeginImageContext(containerSize);
[photo drawInRect:CGRectMake(0.0f, 0.0f, containerSize.width, containerSize.height)];
UIImage *resizedPhoto = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGFloat ratio = photo.size.width / resizedPhoto.size.width;
size = CGSizeMake(resizedPhoto.size.width, photo.size.height / ratio);
return size;

Trying to use visibleCells when scrolling UITableView in iOS

I am building an app where a UIImageView traverses a UITableView programmatically. I have created two buttons ("up" and "down") that control which direction the UIImageView moves. What I am trying to do is programmatically scroll the UITableView if the UIImageView is moving up/down to a row that is not presently visible. I realize I need to use the UITableView method, "visibleCells" to check to see if the cell is within the array is returned. If the cell is not in the array, then I need to scroll the table up/down by precisely one row (each time the user clicks on the "up"/"down" button). Unfortunately I have not come across any good examples on how to use the method, and I need help. Here is the code that I have here:
- (IBAction)buttonClicked:(id)sender {
if([sender tag] == 1){
//here is where I will need to make the call to [_tableView visibleCells] to see if the cell that the UIImageView is about to scroll up to is within this array. If not, then programmatically scroll up one row.
if (_index.row == 0) {
_index = [NSIndexPath indexPathForRow:[_tableData count] - 1 inSection:_index.section];
[_table scrollToRowAtIndexPath:_index atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
else
_index = [NSIndexPath indexPathForRow:_index.row - 1 inSection:_index.section];
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[_table rectForRowAtIndexPath:_index] fromView:_table];
CGFloat floatx = _imageView.frame.origin.x - rect.origin.x;
_imageView.frame = CGRectMake(rect.origin.x + floatx, rect.origin.y, _imageView.frame.size.width, _imageView.frame.size.height);
}];
}
else if([sender tag] == 2){
if (_index.row + 1 == [_tableData count]) {
_index = [NSIndexPath indexPathForRow:0 inSection:_index.section];
[_table scrollToRowAtIndexPath:_index atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
else
_index = [NSIndexPath indexPathForRow:_index.row + 1 inSection:_index.section];
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[_table rectForRowAtIndexPath:_index] fromView:_table];
CGFloat floatx = _imageView.frame.origin.x - rect.origin.x;
_imageView.frame = CGRectMake(rect.origin.x + floatx, rect.origin.y, _imageView.frame.size.width, _imageView.frame.size.height);
}];
}
}
Can anyone show me how to accomplish the functionality that I am trying to achieve?
If you have a little bit time to learn something new, i recommend you to try with iCarousel by #nick-lockwood. Yo can use a vertical iCarousel to achieve something like that:
It's like a UITableView, but for each item in the carousel you can set any UIView, and then you can show a specific item setting the currentItemIndex property!
Take a look if it fits to you. iCarousel saved me two days of work!

Trying to move a UIImageView within a UITableView in iOS

I have developed a simple UITableView that displays a list of items. On top of this UITableView, I have created a selection bar in the form of a UIImageView that moves to whichever row is selected by the user. I have created two buttons (one up, one down) which also controls the movement of this selection bar. When the user clicks the up button, the selection bar moves up exactly one row, and when the user clicks the down button, the selection bar moves down exactly one row. My problem is that when I reach the very top of the table, I want the selection bar to move to the very bottom of the table if the user clicks the up button, and I want the selection bar to go to the very top of the table if the user clicks the down button. Both buttons call the same method (I distinguish between the two buttons based on their tag values). However, when I do this, I am getting the following runtime exception:
2013-06-06 11:34:03.124 SimpleTable[4982:c07] *** Assertion failure in -[UITableViewRowData rectForRow:inSection:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableViewRowData.m:1630
2013-06-06 11:34:03.207 SimpleTable[4982:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path (<NSIndexPath 0x9489850> 2 indexes [0, 10])'
I am not sure why this is happening. Here is my relevant code which is called by my up and down buttons:
- (IBAction)buttonClicked:(id)sender {
if([sender tag] == 1){
if (_index.row == 0) {
_index = [NSIndexPath indexPathForRow:[_tableData count] inSection:_index.section];
}
else
_index = [NSIndexPath indexPathForRow:_index.row - 1 inSection:_index.section];
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[_table rectForRowAtIndexPath:_index] fromView:_table];
CGFloat floatx = _imageView.frame.origin.x - rect.origin.x;
_imageView.frame = CGRectMake(rect.origin.x + floatx, rect.origin.y, _imageView.frame.size.width, _imageView.frame.size.height);
}];
}
else if([sender tag] == 2){
if (_index.row == [_tableData count]) {
_index = [NSIndexPath indexPathForRow:0 inSection:_index.section];
}
else
_index = [NSIndexPath indexPathForRow:_index.row + 1 inSection:_index.section];
[UIView animateWithDuration:.3 animations:^{
CGRect rect = [self.view convertRect:[_table rectForRowAtIndexPath:_index] fromView:_table];
CGFloat floatx = _imageView.frame.origin.x - rect.origin.x;
_imageView.frame = CGRectMake(rect.origin.x + floatx, rect.origin.y, _imageView.frame.size.width, _imageView.frame.size.height);
}];
}
}
Can anyone see what I'm doing wrong?
Thanks in advance to all who reply.
if (_index.row == [_tableData count])
Assuming _tableData is the array that feeds your table, the count of the data in there will be one more than the row of your last index, since indexes are zero-based.
By this I mean, if there are 10 objects in your array, the last row is row 9.
So your check needs to be
if (_index.row + 1 == [_tableData count])
Instead.

Resources