I have an UICollectionView in which each cell contains a PFObject. As there are potentially hundreds of these objects for each UICollectionView, I don't want to query all the objects at once, and instead only call a limited amount, and then automatically call for more as the user scroll towards the end (somewhat like endless scrolling that many web apps use).
Would PFQuery support these type of calls, and if so how would I be able to call continuously and automatically?
Thanks!
Perhaps something like this to get you on the right track:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float scrollViewHeight = scrollView.frame.size.height;
float scrollContentSizeHeight = scrollView.contentSize.height;
else if (scrollView.contentOffset.y <= 0) {
// then we are at the top
}
else if (scrollView.contentOffset.y + scrollViewHeight >= scrollContentSizeHeight) {
// then we are at the bottom - query new results
}
}
I don't think you'd have to add anything for it to call as long as your controller is already your collectionView's delegate.
Related
Is there a way to trigger an event, such as with an IBAction, when a user scrolls to the bottom of a UITableView? I would like to add more rows if this happens. How do I do this?
Unless it´s a little late, but i think i found a better solution:
instead of
- (void)scrollViewDidScroll: (UIScrollView)scroll
i used
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
This is much more convenient, cause the event is only triggered once.
I used this code in my application to load more rows in my tableview at the bottom (maybe you recognize this type of reloading from the facebook application - only difference that they are updating at the top).
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSInteger currentOffset = scrollView.contentOffset.y;
NSInteger maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if (maximumOffset - currentOffset <= -40) {
NSLog(#"reload");
}
}
Hope anyone will help this.
Simply listen to the scrollViewDidScroll: delegate method, compare the content offset with the current possible offset and if lower then some threshold call your method to update the tableview. Don't forget to call [tableView reloadData] to make sure it reload the newly added data.
EDIT: Put together abstract code, not sure if it works, but should.
- (void)scrollViewDidScroll: (UIScrollView *)scroll {
// UITableView only moves in one direction, y axis
CGFloat currentOffset = scroll.contentOffset.y;
CGFloat maximumOffset = scroll.contentSize.height - scroll.frame.size.height;
// Change 10.0 to adjust the distance from bottom
if (maximumOffset - currentOffset <= 10.0) {
[self methodThatAddsDataAndReloadsTableView];
}
}
I use this snippet. in tableView:willDisplayCell:forRowAtIndexPath: I check, if the cell with the last index path is about to be diplayed.
For a tableView with one section:
[indexPath isEqual:[NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]-1 inSection:0]
with more sections:
[indexPath isEqual:[NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]-1 inSection:[self numberOfSectionsInTableView:self.tableView]-1]
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(!_noMoreDataAvailable)
{
if ([indexPath isEqual:[NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]-1 inSection:0]])
{
[self.dataSourceController fetchNewData];
}
}
}
after fetching the dataSourceController will inform the tableView delegate and this will reload the data.
NSInteger currentOffset = scrollView.contentOffset.y;
NSInteger maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
// Hit Bottom?
if ((currentOffset > 0) && (maximumOffset - currentOffset) <= 10) {
// Hit Bottom !!
}
It can be achieved in much simpler way I guess, you just need to determine the scrolling direction as in this case it is when the user is scrolling downwards.
First in your .h file declare a variable :
CGPoint pointNow;
In .m file, in scrollViewDidScroll method we need to implement this code:-
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > pointNow.y) {
//Enter code here
}
}
Swift
Here is the Swift version of #user944351's answer:
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
if maximumOffset - currentOffset <= -40 {
print("reload")
}
}
Just add this method to your UITableView delegate class. I found -40 too large but you can adjust it according to your needs.
More info
See my fuller answer that has an example of method to reload data using limits and offsets for the database.
I'm not sure why you'd want to do this, but I imagine you could add some code to your cellForRowAtIndexPath method so that if indexPath.row == the last row, call the method to add more rows...
I'm trying to move a view while the scrollview is being scrolled with the same intensity.
I'm trying:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// here I detect when user scroll
}
How could I get the intensity that the scrollview is being scrolled?
Try to use these methods:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//scrolling on
NSLog(#"scrollViewWillBeginDragging");
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if(!decelerate) {
//not scrolling
}
NSLog(#"scrollViewDidEndDragging");
}
You can do that by reading the contentOffset property on the scrollView
// You can save this as a property or an iVar
CGPoint lastContentOffset;
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
lastContentOffset = scrollView.contentOffset;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint difference = CGPointSubstract(scrollView.contentOffset, lastContentOffset);
lastContentOffset = scrollView.contentOffset;
// Use difference to know by how much the scroll view scrolled
// IMPORTANT: CGPointSubstract is not a standard function, you can implement it yourself.
}
I don't want to give you the full code but i'll help with how to achieve it.
1) You need to use the time.
2) When the time difference is greater than an amount of time passed to measure (0.05s?)
3) Check what the old content offset is compared to the new one
4) The difference is your velocity
5) reset your current timer
6) set current offsets to last offset
Hope this helps
Ben
distance calcs
CGFloat distanceY = currentOffset.y - lastOffset.y;
CGFloat distanceX = currentOffset.X - lastOffset.X;
I'm trying to limit the scroll speed of my UITableView, exactly like Instagram does it.
If you check out Instagram, you'll notice that they have a limit on how fast you can scroll through the feed.
It's not set using "decelerationRate" since the limit doesn't affect the deceleration. It simply affects the how fast you can scroll through the feed. So if you try to do a "flick" gesture, you will hit Instagrams max scrolling speed and won't go as fast as in a normal UITableView.
Any guesses on how Instagram accomplishes this?
TableView has a property scrollView, This property will return internal scrollView of TableView. Use following...
tableview.scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
ANOTHER WAY:
TableView will respond to scrollView delegate, so we need to implement scrollView's delegate like:
Take these global variables :
CGPoint lastOffset;
NSTimeInterval lastOffsetCapture;
BOOL isScrollingFast;
Implement scrollViewDidScroll like :
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint currentOffset = scrollView.contentOffset;
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval timeDiff = currentTime - lastOffsetCapture;
if(timeDiff > 0.1) {
CGFloat distance = currentOffset.y - lastOffset.y;
//The multiply by 10, / 1000 isn't really necessary.......
CGFloat scrollSpeedNotAbs = (distance * 10) / 1000; //in pixels per millisecond
CGFloat scrollSpeed = fabsf(scrollSpeedNotAbs);
if (scrollSpeed > 0.5) {
isScrollingFast = YES;
NSLog(#"Fast");
} else {
isScrollingFast = NO;
NSLog(#"Slow");
}
lastOffset = currentOffset;
lastOffsetCapture = currentTime;
}
}
Then implement scrollViewDidEndDragging like this :
- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if( !decelerate )
{
NSUInteger currentIndex = (NSUInteger)(scrollView.contentOffset.x / scrollView.bounds.size.width);
[scrollView setContentOffset:CGPointMake(scrollView.bounds.size.width * currentIndex, 0) animated:YES];
}
}
Hope this may help you...
Use this:
self.tableview.scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
As tableView is a subclass of UIScrollView, ScrollView delegate will work here. Hope this helps.. :)
Edit:
if tableView doesn't show scrollView property use:
self.tableView.decelerationRate
In Swift set like this
tableView.decelerationRate = UIScrollView.DecelerationRate(rawValue: 0.5)
UIScrollView.DecelerationRate having two rate types normal and fast. By default its normal (approx value >= 0.9). didn't check about fast value.
To do like Instagram you need to check velocity using scrollViewWillEndDragging method.
check velocity, if its above some threshold then set decelerationRate as per your need.
I want to change the height of my UITableView based on the scrolled content. Right now I do it by getting the scrollViewDidScroll event and then getting scrolled value and then change the height. Here is my code (for simplification I omitted the irrelevant code):
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
float currentOffset = scrollView.contentOffset.y
double delta = currentOffset - storedOffset;
if(delta != 0)
{
delta = abs(delta);
CGRect newListFrame = myTableView.frame;
float newListHeight = newListFrame.size.height + delta;
newListFrame.size.height = newListHeight;
myTableView.frame = newListFrame;
}
storedOffset = currentOffset;
}
But this approach is wrong because with this approach my UITableView's content is scrolled only a little bit and that's not what I want. I just want to get the value of that list that would be scrolled without actually scrolling it. Is there any way to do that? I thing I could get raw finger moved event but can I get it on UITableVIew? Can I do something like this using a UITableView method?
I have a UITableview that I'm trying to append data to when the user scrolls near the bottom. I've written this method to detect the scroll and it functions correctly but looks bad.
- (void)scrollViewDidScroll:(UIScrollView *)scroll {
NSInteger currentOffset = scroll.contentOffset.y;
NSInteger maximumOffset = scroll.contentSize.height - scroll.frame.size.height;
if (maximumOffset - currentOffset <= 5) {
[self loaddata:[NSString stringWithFormat:#"%d", celltitle.count]];
}
}
loaddata has a number passed to it which is used to limit the returning cells from the database correctly. i.e. LIMIT x, (x+20)
Like I said the data loads but each time it goes to load it the scrolling pauses and then resumes. The NSURLConnection is synchronous. Could that be a problem?