Programmatically force a UIScrollView to stop scrolling, for sharing a table view with multiple data sources
Asked Answered
H

10

25

I have a UITableView whose data source and delegate are switched between a couple of custom data source objects when the user touches a segmented control (think "Top Paid" vs "Top Free" in the app store app).

Each data source object saves its last scroll content offset, and restores it when it becomes the active data source for the table view by doing:

tableView.contentOffset = CGPointMake(0, savedScrollPosition);

This works well when the user switches the data source when the table is at rest, but if the user hits the segmented control while the table is still moving (i.e. decelerating), the table view continues to decelerate from the old offset, effectively overriding my contentOffset assignment.

Is there a way to force the table view to stop scrolling/decelerating when I set the contentOffset, or another way to make this type of switchable-data-source table view work?

Holmic answered 12/6, 2009 at 12:33 Comment(0)
L
20

Did you try these 2 methods?

They actually apply to the "scrolling" not just the offset of the content.

[self.tableView  scrollToRowAtIndexPath:savedIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];

OR:

[self.tableView  scrollRectToVisible:savedFrame animated:NO];

They should actually effect the scrolling and by extension the acceleration of the table, not just what is visible on screen.

Lunch answered 12/6, 2009 at 17:35 Comment(1)
scrollRectToVisible did it, using the saved scroll position as the rect's origin and using the table view's bounds as the height. You are absolutely correct that the scroll* methods control the acceleration in ways setting the content offset doesn't.Holmic
S
13

Have you tried using [view setContentOffset: offset animated: YES]?

Sconce answered 12/6, 2009 at 13:59 Comment(3)
I'll give it a shot. It's not exactly the behavior I want (I want the scroll position to snap right away), but it might be good enough.Holmic
Works great with animated:YES. (Stops right away). Also works great with the collectionView on a UICollectionViewController.Hilel
This should be the accepted answer as it even uses a CGPoint for the offset like the question intended.Visual
D
5

This worked nicely for me:

if (self.tableView.isDecelerating) {
        NSArray *paths = [self.tableView indexPathsForVisibleRows];
        [self.tableView scrollToRowAtIndexPath:[paths objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];

    }
Denunciation answered 18/4, 2012 at 11:21 Comment(0)
P
4

Just found this looking for a way to stop my UIScrollView - I needed to move some subviews around, but this wound't look right if the user had flicked the screen and it was still decelerating.

Anyway - scrollRectToVisible didn't work for me (maybe because I'm not using a table view??) but this worked perfectly:

[mainScrollView setContentOffset:CGPointMake(mainScrollView.contentOffset.x, mainScrollView.contentOffset.y) animated:NO];

I can then do the subview stuff without worrying!

Peloquin answered 11/8, 2010 at 13:33 Comment(0)
P
2

I used Corey's approach. I save & restore the rects with the dictionary representation. Also, it may not be obvious but the rect to preserve & restore is the bounds of the UITableView:

// Save the current tableview bounds
CGRect contentRect = self.listTableView.bounds;
if (!!oldScope) [_contentRects setObject:(NSObject *)CGRectCreateDictionaryRepresentation(contentRect) forKey:oldScope];

// Restore if possible
CFDictionaryRef restoredFrameDict = (CFDictionaryRef)[_contentRects objectForKey:newScope];
if (!restoredFrameDict) restoredFrameDict = CGRectCreateDictionaryRepresentation(CGRectZero);
CGRectMakeWithDictionaryRepresentation(restoredFrameDict, &contentRect);

// Switch over to new datasource
self.listTableView.dataSource = [self dataSourceForScope:newScope];
[self.listTableView reloadData];

// Restore content offset for "newScope"; Also stops scrolling
[self.listTableView scrollRectToVisible:contentRect animated:NO];

Note the interchangeable use of CFDictionaryRef and NSDictionary *

Prohibit answered 17/5, 2010 at 22:59 Comment(0)
L
0

You could wait for the 'decelerating' property to become NO (e.g. by using KVO) and switch after that.

Leopoldoleor answered 12/6, 2009 at 13:43 Comment(1)
The problem with that is that there would be a rather noticeable delay before the scroll position can be set.Holmic
H
0

One obvious work around is to have two separate table views that get swapped out, and each data source is permanently attached to one of the table views. This just seemed like a bit of a waste of memory, but perhaps I'm over-thinking it.

Holmic answered 12/6, 2009 at 14:13 Comment(0)
S
0

It was my problem when I had a UISwitch as selector for the tables. But with the segmented control I haven't any problem. Maybe you didn't reload the table? This is my piece of working code:

NSIndexPath *exPath = [[subTable indexPathsForVisibleRows] lastObject]; 

isMatchOn = [whatList selectedSegmentIndex] == 0 ? YES : NO;  //table source will make the choice looking at this BOOL  

[subTable reloadData];  // here tables actually flip

if (lastPosition) {
    [subTable scrollToRowAtIndexPath:lastPosition atScrollPosition:UITableViewScrollPositionBottom animated:NO];   //I scroll to saved index
    }
self.lastPosition = exPath;  //here I save the current position
Something answered 15/9, 2010 at 17:57 Comment(0)
A
0

You can also do self.tableView.isScrollEnabled = true/false when you get to a certain tableView.contentOffset.y value

Asphyxiate answered 7/4, 2017 at 15:16 Comment(0)
B
-3

You could try doing

tableView.scrollEnabled = NO;
tableView.scrollEnabled = YES;

This might stop the scroll by disabling it, then allow it again. I haven't tried this specifically, but I've done similar things.

Brace answered 12/6, 2009 at 13:39 Comment(1)
I tried setting it to NO, then set the contentOffset, then set it back to YES. That didn't work, but I might as well try the sequence NO-YES-offset and see if that makes a difference.Holmic

© 2022 - 2024 — McMap. All rights reserved.