Scroll one cell at a time in collection View - ios

Using the willDisplayCell method I got the index of the last visible cell:
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
indexVisibleCell = [indexPath indexAtPosition:[indexPath length] - 1];
}
where indexVisibleCell is an NSUInteger that is declared in the class' interface. My problem is that I want to shift only one cell when user taps on the right or left button. I have applied this code for that purpose:
- (IBAction)rightButton:(id)sender {
NSUInteger indexOfScrolledCell;
indexOfScrolledCell = indexVisibleCell;
if (indexVisibleCell < 9) {
NSIndexPath *path = [NSIndexPath indexPathForRow:indexOfScrolledCell+1 inSection:0];
[self.obj_CollectionView1 scrollToItemAtIndexPath:path atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}
}
as I show 3 cells at a time. By using that rightButton action method it shifts 3 cells at a time, not one. Please help me figure out how to scroll one cell at time.

Try using UICollectionView with paging enabled. Use following code, hopefully it works out for you.
[yourCollectionView setPagingEnabled:YES];

Use visibleCells to get your visible Cells, get the leftmost Cell index to figure out the next index, then scroll to that Cell on the left (similar logic to your code).
willDisplayCell is not reliable since it is called both times when you scroll left/right, and you're thinking that index is the left/right most is not correct.
Edit:
Or you need to compare the index in willDisplayCell correctly, to get the correct left/right most index, based on your logic.

For right button you can use following
[self.obj_CollectionView1 scrollToItemAtIndexPath:path atScrollPosition:UICollectionViewScrollPositionRight animated:YES];
and for left button following
[self.obj_CollectionView1 scrollToItemAtIndexPath:path atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
I am changing UICollectionViewScrollPosition so that when you scroll to right new item shows up on right side of collection view and when you scroll to left new item shows on left side of collection view.

Related

Getting first Cell/Item of UICollectionView while scrolling - iOS

I have a UICollectionView with 1 row 1 column. I want to get the first item (indexPath basically) when I am scrolling it horizontally.
For example, I have got 100 items displayed horizontally in my UICollectionView and when I scroll from right to left, whichever item is the first one visible, I need its indexPath.
Which means the indexPath will be constantly changing while its scrolling.
How to achieve this? Please Guide. Thanks!
collectionView.indexPathsForVisibleItems() returns an array of NSIndexPath for visible cells. You can get the left most one by sorting them by NSIndexPath.item.
Edti:
To be notified while scrolling, implement the UIScrollViewDelegate method scrollViewDidScroll(_: UIScrollView). Remember that UICollectionView is a subclass of UIScrollView.
I think you need implement UIScrollView delegate method and get visible cell inside
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
UICollectionViewCell *firstCell = [[collectionView visibleCells] firstObject];
NSIndexPath *firstIndexPath = [collectionView indexPathForCell: firstCell];
NSLog(#"%#", firstIndexPath);
}
Hope this help

Scroll past section header upon tapping section index?

I've implemented a UITableView that has section headers above each section. I've designed the table with the Grouped style so the headers scroll with the table instead of fixing to the top. I have also added a section index so users can tap/swipe to jump to a specific section. The problem is doing so jumps to that section but it shows the section header at the top. In this case that's undesirable - I want to scroll so the very top of the first cell is at the top of the screen, with that section header not visible.
How can you scroll just past the section header when the user taps an icon in the section index for UITableView?
Just try this
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 section:desiredSectionIndex];
[tableView scrollToRowAtIndexPath: indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Found a solution. Perhaps there is a cleaner solution but this is working well for me.
Return -1 to prevent the table view from scrolling to any section when that method is called. Just before the return, add the logic to scroll to the desired location by getting and modifying the frame of the next cell.
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
CGRect nextRowRect = [tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:index]];
nextRowRect.origin.y -= tableView.rowHeight;
nextRowRect.size.height += tableView.frame.size.height - tableView.contentInset.top - tableView.contentInset.bottom - tableView.rowHeight;
[tableView scrollRectToVisible:nextRowRect animated:NO];
return -1; //prevent auto scroll
}

scrollToRowAtIndexPath doesn't scroll to correct position when segment value changed

I have a segment control with a table view. When user clicks segment control, then table view changes data source. I would like table to scroll to last position user had seen.
For example: user was in segment 1 and looking at table view line 3.
segment 1 | segment 2
line 3
line 4
line 5
Then user clicked segment 2 then clicked back to segment 1. I want table view scroll to line 3.
Code is as below. In viewDidAppear I have same code to get lastSavedRow and call scrollToRowAtIndexPath. When app gets loaded the scrolling works. However, in segmentValueChanged action it doesn't roll to correct position. In debugger I am sure the lastSavedRow has correct number.
- (IBAction) segmentVauleChanged : (id)sender
{
// remember row number before segment value changes
NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
NSArray * sortedIndexPaths = [indexPaths sortedArrayUsingSelector:#selector(compare:)];
NSIndexPath *firstVisibleIndexPath = [sortedIndexPaths objectAtIndex:0];
// function to write row number and seg index to user default
[self saveScrollPositionInSegment: self.currentSegmentSelectedIndex row:firstVisibleIndexPath.row];
self.currentSegmentSelectedIndex = segmentController.selectedSegmentIndex;
[self.tableView reloadData];
// scroll to last saved position
int lastSavedRow = [self getScrollPositionInSegment:segmentController.selectedSegmentIndex];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:lastSavedRow inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Does anyone have same problem? Many thanks in advance!
The lastSavedRow will on the top of the current tableview. I think there maybe something wrong with the dealing with datasource. Maybe after change the datasource, the last postion the user seen was not the index you figured out!
If you provide more information or your example, we can help you to find out the mistake.
I would do the following.
1 .Call visibleCells before calling indexPathsForVisibleRows
[self.tableView visibleCells];
2.Look at the need for sorting the array before identifying firstVisibleIndexPath
3.reloadData is not synchronous so its possible that the table is not completed loading before you try to scroll to an index. So try to see if you can do the scrolling in one of the delegate functions instead of here. See this.
hackerinheels 's (3) is right. reloadData hasn't finished when scrolling table is called. So I added the code:
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
if (section == ([self.tableView numberOfSections] - 1)) {
//NSLog(#"finish loading");
// put the scrolling table call here: [self scrollTableView ];
}
return nil;
}
Thank you all for helping!

How to bring a certain cell to front

In my table view, I have three sections, of which the first section contains a image cell, the second section contains segment control cell, and the third section contains some label cells.
What I am doing is when the user scrolls up the table view, everything will scroll up but the position of the segment control cell will be fixed at the upper margin of the screen.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSIndexPath *indexPathOfCurrentHeaderCell = [NSIndexPath indexPathForRow:0 inSection:0] ;
UITableViewCell *headerCell = [self.tableView cellForRowAtIndexPath:indexPathOfCurrentHeaderCell];
if (headerCell.frame.origin.y < self.tableView.contentOffset.y)
{
self.cellHead.hidden = NO;
self.cellHead.frame = CGRectMake(0, self.tableView.contentOffset.y, self.cellHead.frame.size.width, self.cellHead.frame.size.height);
}
[self.tableView bringSubviewToFront:self.cellHead];
}
But the function bringSubviewToFront: does not seem to work here (the second section will be covered by the third section). I think it is because the cells are not the subviews of the table view.
What can I do if I want to pull the segment control cell to the front?
You should add the segment control as a header instead of a cell in the tableview, using
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
then, you would have 2 sections,
1. image cell
2. segment control as header, labels as the cells

Selecting one UITableViewCell selects the other cells at that same position when you scroll up or down

I have a UITableView with Dynamic Prototypes.
I implemented the code below so that when I select a row, it will be marked and the previously selected row will be unmarked.
However, for example, the row I selected is displayed in the middle of the screen, then when I scroll up or down, another cell (which is in the same middle position of the screen) is marked. In short, every view, there is a selected cell at the middle.
Please advise.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *oldIndexPath = [self.tableView indexPathForSelectedRow];
[self.tableView cellForRowAtIndexPath:oldIndexPath].accessoryType = UITableViewCellAccessoryNone;
[self.tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
return indexPath;
}
Probably you are overwriting accessoryType in your cellForRowAtIndexPath method - this is called each time table is about to draw new rows which were invisible before (as you described when you scroll up / down).
You need to handle it also in that function and update accessoryType there - otherwise it will randomly reuse a cells with different accessoryTypes.
You are modifying just the visuals of cell, you're not updating the data model. Store the selected index path in a #property somewhere, and adjust accessoryType inside cellForRowAtIndexPath.

Resources