I use scrollToItemAtIndexPath:atScrollPosition:animated to scroll UICollectionView. I have to disable some functionality while this automatic scrolling is happening and then re-enable it, when scrolling ends. The problem occurs, when I try to scroll to some cell which is already visible and there is no scroll necessary (for example, it's the last cell and collection view is already scrolled until the very end). In this case scrollViewDidEndDragging nor scrollViewDidEndDecelerating are called.
Is there a way to know if scrollToItemAtIndexPath will actually scroll UICollectionView?
I Think you can save the latest scroll view offset & track changes in it every time the scrollView scrolls & apply actions after significant changes only.
func scrollViewDidScroll(scrollView: UIScrollView) {
let scrollOffset = scrollView.contentOffset.y;
if scrollOffset < (previousValue-100) || scrollOffset > (previousValue+100)
{
// Scrolled up or down with 100 points which you can change
previousValue = scrollOffset
}
}
You can determine whether scrollToItemAtIndexPath will scroll based on the cell's frame before calling scrollToItemAtIndexPath. For example, if you just want the cell to be visible (UICollectionViewScrollPositionNone):
UICollectionViewLayoutAttributes* attrs = [collectionView layoutAttributesForItemAtIndexPath:indexPath];
CGRect frame = [collectionView convertRect:attrs.frame toView:self.view];
BOOL willScroll = !CGRectContainsRect(collectionView.frame, frame);
It's unfortunate that scrollToItemAtIndexPath doesn't simply tell you whether it will scroll.
Related
I have a new design for my app and it include a parallax scroll for a image display on top of tableView.
I know how to add a parallax effect with putting a image in to a cell, like this -
when table scrollViewDidScroll get called :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint currentOffset = scrollView.contentOffset;
if (currentOffset.y > _lastContentOffset.y) {
//Scroll Up
_containerView.clipsToBounds = true;
_bottomSpaceConstraint.constant = -scrollView.contentOffset.y / 2;
_topSpaceConstraint.constant = scrollView.contentOffset.y / 2;
} else {
//Scroll Down
_topSpaceConstraint.constant = scrollView.contentOffset.y;
_containerView.clipsToBounds = false;
}
_lastContentOffset = currentOffset;
}
(the _bottomSpaceConstraint and _topSpaceConstraint are the Image top and Bottom constraint which inside the tableView cell in section 0)
But my problem is I needs to stop the image scrolling up when it reached the size of my navigation bar. (my navigation bar background is transparent) I don't want the image to go all the way top. But it is a cell which is inside my tableView so it is going all the way to top until it disappear when scrolling. I need help for stop this image get scrolled. Maybe my approach is not correct if I want to achieve this effect.
This effect is on android and its called "collapsing toolbar layout".
http://antonioleiva.com/collapsing-toolbar-layout/
Does someone know how to do this "collapsing toolbar layout" effect for iOS.
Thanks a lot for any help!
Try creating a UIView that will contain the image and set the tableHeaderView in the tableView. Then in scrollViewDidScroll: update the height and top constraints of the header view.
There is a button at the bottom of my view controller. When the user scrolls down the button has to be attached to the scrollview at certain height.
I need to attach a button to the scrollview, immediately when the contentOffset.y reaches a particular value. -(void) scrollviewDidScroll doesn't help me as there might be a jump in contentOffset when the user is scrolling fast. Any leads on this are helpful.
Also, whenever I add a subview to the scrollview, -(void) viewDidLayoutSubviews is called. Which in turn sets the contentOffset to {0,0}. How can I achieve the functionality I need?
I needed to do the same thing with a UITableView and for me using scrollViewDidScroll worked.
I created a view called staticBar and added it as a subview of the tableView, but I had to rearrange the tableview subviews for it to appear in the right place. I don't have my code in front of me, but in -scrollViewDidScroll: it looked something like this:
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
CGFloat staticBarAdjustedY = _staticBarY - scrollView.contentOffset.y;
CGFloat scrollViewYFloor = scrollView.frame.size.height - _staticBar.frame.size.height;
// This way maximum Y the view can have is at the base of the scrollView
CGFloat newY = MIN( staticBarAdjustedY, scrollViewYFloor);
_staticBar.frame = (CGRect){ { _staticBar.frame.origin.x, newY}, _staticBar.frame.size}
}
I will check my code later today and add more details here.
Also, you said the scrollviewDidScroll has jumps in contentOffset, but it's worth mentioning that these jumps are the same that the scrollView uses to scroll its own view. So it's not like you are "losing" frames on this delegate method.
Hope it helps.
PS: So, here is the rest of my code.
//I place my custom view as a subview of the tableView below it's last subview
//The last subview is for scroll indicators.
WTButtonsBar *buttonBar = [[WTButtonsBar alloc] init];
[self.tableView insertSubview:buttonBar belowSubview:self.tableView.subviews.lastObject];
In scrollViewDidScroll:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//In my app I needed my view to stick to the top of the screen
//thats why I use MAX here
//self.buttonsBarOriginalY is the view's position in the scrollView when it isn't attached to the top.
CGFloat newY = MAX(scrollView.contentOffset.y, self.buttonsBarOriginalY)
[_buttonsBar setFrame:(CGRect){{0, newY}, _buttonsBar.frame.size}];
}
I need some help.
I have UIcollectionView, I am using scrollToItemAtIndexPath:atScrollPosition:animated: Method. I need somehow to recognize if collection view will scroll to position or if item on needed position and will no scroll.
Another words, if scrolling will not start, scroll view delegate methods will not be called.
Thanks for help
How about checking if the indexPath you're interested in is in [UICollectionView indexPathsForVisibleItems]?
You can also use layoutAttributesForItemAtIndexPath to get the exact frame of the cell to determine if its partially shown.
You can use
CGRect cellFrame = [collectionView.visibleCells.lastObject frame];
CGRect collectionViewVisibleRect = collectionView.bounds;
collectionViewVisibleRect.origin.y = collectionView.contentOffset.y;
if (CGRectContainsRect(collectionViewVisibleRect, cellFrame))
//no scroll
else
//scroll
That does not takes into account contentInset that you might have.
Is it possible to recognise gesture from scrollView so when one scrollView is dragged to simulate same dragging on another scrollView? For example I have tableView with custom cell that have scrollView in it, and I want to simulate dragging on every item in list.
EDIT
I succeeded to recognize movement of scrollView, but now I cant set other scrollViews from table to do same amount of scrolling.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
int position_x = scrollView.contentOffset.x;
int i=0;
int indexPath = [self.tableView indexPathForSelectedRow].row;
static NSString *hlCellID = #"EPGCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:hlCellID];
UIScrollView *scrollView = (UIScrollView *)[cell viewWithTag:16];
for(i=0; i<EPGList.count;i++){
if(i!=indexPath){
scrollView.contentOffset = CGPointMake(position_x, scrollView.frame.size.height);
}
}
}
Problem is that indexPath is not returning correct value when i am clicking on scrollView. It returns correct value only when I am clicking on cell space outside of scrollview.
Yes, yes it is possible. You need to have a delegate assigned to the scrollViews within the cells. Preferrably the same class that implements hour tableview data source and table view delegate protocols. You must implement UIScrollViewDelegate and the delegate must implement the scrollViewDidScroll: method.
Within that scrollViewDidScroll delegate method, you check the contentOffset property for its x and/or y values. Normally people go for the vertical scrolling value, but if you're implementing them in a UITableViewCell, you're probably doing horizontal scrolling.
The you use the value, I am assuming contentOffset.x, to update other scroll views within the other cells of your table! Make sense?
I have just posted an answer to another UIScrollView question yesterday. Please read what I wrote there, it might help you more.
Animation in UIScrollView iOS app
I have a horizontal UITableView where I would like to set the paging distance. I tried this approach,
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
_tableView.decelerationRate = UIScrollViewDecelerationRateFast;
CGFloat pageSize = 320.f / 3.f;
CGPoint contentOffset = _tableView.contentOffset;
contentOffset.y = roundf(contentOffset.y / pageSize) * pageSize;
[_tableView setContentOffset:contentOffset animated:YES];
}
This works when you scroll slowly and let go but if you scroll fast, there's a lot of popping. So after wrestling with it for a bit, I'm trying a different approach...
I'm simply enabling paging on the tableView and then setting the width of the table to my desired paging size (a 3rd of the screen's width). I also set clipsToBounds = NO. When I use this approach, the scrolling works as expected but now cells outside of my smaller table width do not draw. What I would like is to force the cell on the left and right of my current cell to draw, even though they are outside of the UITableView's frame. I know cellForRowAtIndexPath get's called from a deeper level but is there some way I can trigger it myself for the cell's I selected?
I've tried using,
[[_tableView cellForRowAtIndexPath:indexPath] setNeedsDisplay];
but it does nothinggggggg!