Programmatically force a UIScrollView to stop scro

2019-01-16 16:31发布

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?

10条回答
我命由我不由天
2楼-- · 2019-01-16 17:20

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 *

查看更多
Lonely孤独者°
3楼-- · 2019-01-16 17:22

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!

查看更多
霸刀☆藐视天下
4楼-- · 2019-01-16 17:25

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.

查看更多
霸刀☆藐视天下
5楼-- · 2019-01-16 17:26

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.

查看更多
登录 后发表回答