Maybe I made a wrong description for what I want and hence haven't hit any answer, if that's the case please kindly provide a link with solution.
what I want is:
I have scrollview, alwaysBounceVertical is set to true. So when the user drags down after the scrollview has already reached top, the scrollview should bounce. More specific: the view moves down as the user drags, and the moment the user releases his finger the scrollview bounces back.
The event I want to catch is the one that the scrollview finishes bouncing back. I want to apply an animation after this point. So could anyone tell me how should I modify which method in UIScrollViewDelegate to catch that event?
you can just use UIscrollView Delegate methods Apple Documentation and this an example
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if(!decelerate){
// Do something
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// Do something
}
for your problem you can apply your behaviour on scrollViewDidEndDragging
i think this methods will help you
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0);
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
Related
I am trying to create a function that is only called after a CollectionView is scrolled or dragged a certain distance and is called repeatedly every time the distance is scrolled.
I also need this function to be called 1 time initially after the CollectionView has been loaded. How could I accomplish this for an Objective-C iOS application?
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//do something
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(#"%f %f", self.tableView.contentOffset.x, self.tableView.contentOffset.y);
}
I think you'll need this.
How would you go about implementing a UICollectionView with this behaviour?
The idea is that once a user navigates past a certain point, they cannot go back and view those cells again.
My attempt at a solution has been to listen for gestures on the collection view and if disable scrolling once a swipe occurs on the element. The obvious problem with this is that the user can simple hold and drag any particular cell.
Any thoughts?
I think this behavior may be confusing for your users.
Maybe you should try to add some elasticity/bouncing so that your users would be less confused.
Anyway, I see two different ways to achieve this without subclassing
1/ Since UICollectionViewDelegate conforms to UIScrollViewDelegate, you can get the starting offset of your scrollview with – scrollViewWillBeginDragging: then in – scrollViewDidScroll: you would compare the new offset's x value. If the new offset.x 's value is smaller than the starting one, set it to 0 and update your scrollview.
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
offset = scrollView.contentOffset;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint newOffset = scrollView.contentOffset;
if (newOffset.x < offset.x) {
// scrolling to the left, reset offset
[scrollView setContentOffset:offset];
}
}
Because there is inertia with scrolling in iOS, scrollViewDidScroll: is called a lot of time, so it may cause performance issues. You may reduce the number of call by targeting your offset with scrollViewWillEndDragging:withVelocity:targetContentOffset: from UIScrollViewDelegate.
2/ Or ou can just use the method scrollViewWillEndDragging:withVelocity:targetContentOffset: which I just spoke about, which sets the offset back to its beginning, with an animation.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGPoint newOffset = scrollView.contentOffset;
if (newOffset.x < offset.x) {
// scrolling to the left, reset offset with animation
targetContentOffset->x = offset.x;
}
}
3/ You spoke of UISwipeGestureRecognizer, did you give a try to UIPanGestureRecognizer? This is what "simple hold and drag" is.
You can implement it the same way you would implement an infinite scroll view, by adding / removing items based on the scroll offset.
Override the viewDidScroll: method (UICollectionViewDelegate)
Check if your offset puts the first object of your list past the offset (ie. can you still see it on the screen?)
If it is, then remove it from the collection view.
This simple implementation might result in choppy animations, you might have to do some optimization once it's working but this should get you started.
Another possible solution would be to "reposition" all your elements constantly to appear where they were before you started scrolling if you are scrolling left.
You can achieve this by keeping track of the highest offsetX you ever encountered, and reposition your cells if the current offsetX is lower than the max. That way you will have the impression that your cells are not moving or that you can't scroll, but you will actually be scrolling.
In my case, I have a paginated collection view, so I have to take care when decelerating in the last item of the collection view as well in automatic decelerations for each page.
To fix the issue, I just disable user interaction while the collection view is "moving automatically".
Here the code:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (!_isDragging) // <-- only do things if the user is dragging!
return;
CGPoint contentOffset = scrollView.contentOffset;
// If we move to the left
if (contentOffset.x < _contentOffset.x)
{
CGSize contentSize = scrollView.contentSize;
// If content offset is moving inside contentSize:
if ((contentOffset.x + scrollView.bounds.size.width) < contentSize.width)
scrollView.contentOffset= _contentOffset;
}
else
{
// Update the current content offset
_contentOffset = contentOffset;
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
_isDragging = YES;
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
_isDragging = NO;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (decelerate)
{
// If willDecelerate, stop user interaction!
_collectionView.userInteractionEnabled = NO;
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
// Once deceleration is finished, enbale user interaction
_collectionView.userInteractionEnabled = YES;
// Set the new content offset
_contentOffset = scrollView.contentOffset;
}
I want to revert my UIScrollView's content offset if I don't drag enough:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(CGPoint *)targetContentOffset {
self.endingOffset = scrollView.contentOffset;
if(abs(verticalOffset) > [self cellHeight] / 9) { // If the user scrolled enough distance, attempt to scroll to the next cell
...
} else if(self.nextCellOrigin.y != 0) { // The scroll view is still scrolling and the user didn't drag enough
...
} else { // If the user didn't drag enough
self.tableView.decelerationRate = UIScrollViewDecelerationRateNormal;
(*targetContentOffset) = self.startingOffset;
}
}
The code to revert to the original position is in the else portion, and it always works. However, when I don't scroll enough and make the gesture quickly, it snaps back. If I scroll just a little and then hold that position for slightly longer than usual, it reverts back smoothly.
I haven't found anything in the API reference for how long a user has touched a UIScrollView, and even if I did it's not immediately obvious how I could use that to change the behavior of my reverting code. I've also tried scrolling to the position with setContentOffset:animated: but that doesn't seem to fix the jerkiness.
Any ideas?
Have you tried logging the velocity to find out how it is when the jerkiness happens?
EDIT:
What you can try to do is implement these two scrollView delegate methods instead of the willEndDragging method. This solution will give a different feeling to the scrollView, but give it a try.
Fill the checkOffset method with all the logic you need.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
// if scrollView's contentOffset reached its final position during scroll, it will not decelerate, so you need a check here too
if (!decelerate) {
[self checkOffset];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self checkOffset];
}
- (void)checkOffset {
CGPoint newOffset;
...
// Do all the logic you need to move the content offset, then:
...
[self.scrollView setContentOffset:newOffset animated:YES];
}
EDIT #2:
Maybe you could achieve a better result if you also add this to my solution.. Try ;)
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(CGPoint *)targetContentOffset {
// This should force the scrollView to stop its inertial deceleration, by forcing it to stop at the current content offset
*targetContentOffset = scrollView.contentOffset;
}
I've got a re-orderable table view (UITableView instance). Although I've implemented the UITableViewDataSource method:
tableView:moveRowAtIndexPath:toIndexPath:
This only fires on drop of the moved table cell.
I want a callback that tells me that a cell has just been gripped by it's reordering control and is about to take flight. I didn't catch this in the API.
Purpose: As soon as a move operation is even being flirted with, I'd like to remove other decorations on my main view that are no longer valid. Ideally, I'm looking for something like a call back (I can wish right!) that read like this:
tableView:didBeginPossibleMoveOfRowAtIndexPath:
Neither UITableViewDataSource nor UITableViewDelegate protocols give me hooks for this. Or did I miss something?
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
use this now when you will start to scroll the tableview then
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
will start to work.
when you are scrolling then
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
will call.
At the end of your scrolling this method will start to work,
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
I hope you have understood.May be it will help you.
Thanks
Is there any event in table view which will get triggered when i try to scroll the table view.
I want to create a down arrow image to the bottom of the table view ,when the user tries to scroll through the table view.Any help will be appreciated.
Thanks,
Christy
As far as i recall, since UITableView Inherits from UIScroll view you can listen to the UIScrollViewDelegate methods:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
{
}
Any way. make sure that
tableView.delegate=self;