I want to animate the top and bottom most cells in a UICollectionView as they enter and leave the screen. I don't just want to animate using scrollview delegates and a one time animation. I want the animations to be progress driven.
Example: Top most cell gradually fades away as cell scrolls farther offscreen.
I have scoured the internet for a way to do this, but the solutions are either way outdated or don't achieve this effect. Thanks in advance.
You could try to use NSCollectionLayoutSectionVisibleItemsInvalidationHandler
let section = NSCollectionLayoutSection(group: group)
section.visibleItemsInvalidationHandler = { visibleItems, scrollOffset, layoutEnvironment in
// perform animations on the visible items
}
If you know height of cells, you could track with scrollOffset when top cells will be scrolled away and add animations.
When a new item is added to visibleItems, you could apply to it animations too. Also if a new item is added, than the top one will be replaced, so you could work just with visibleItems for both cases.
Related
hi... really how do they implement this? there are several tutorial for Twitter profile page. but they don't handle all possibilities...
first... when you scroll top or bottom any where, top view start scrolling until the segmented control, reach at top of the page...then scroll doesn't stop and subtable start scrolling until touching down and middle of way tableview start loading other rows dynamically ... so I don't think that they set content of scrollview statically
second things how do they handle sub tables... are they containerView?
if so, then the structure would be like this
ScrollView
TopView (User Info)
Segmented Controll
scrollView(to swipe right or left changing tables)
ContainerView For TWEETS
ContainerView For TWEETS & REPLIES
ContainerView For MEDIA
ContainerView For LIKES
am I right?
so how do they handle scrolls between sub tables and Top Scroll View to implementing topview position change base on scrolling...
it's mind blowing
this is How I Handel Nested ScrollViews...
i made a childDidScroll Protocol and my child tableviews implement that and in my profile page i can receive all child didscroll event then in
childDidScroll method :
//if child scrollview going up
if(scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0)
{
//check top scrollview if it is at bottom or top
//then disable the current scrollview
if mainScrollView.isAtBottom && scrollView.isAtTop{
scrollView.isScrollEnabled = false
}else{
//else enable scrolling for my childs
featuresVC.tableView!.isScrollEnabled = true
categoriesVC.tableView!.isScrollEnabled = true
shopsVC.tableView!.isScrollEnabled = true
}
print("up")
}
else
{
if mainScrollView.isAtTop {
scrollView.isScrollEnabled = false
mainScrollView.scrollToBottom()
}else{
featuresVC.tableView!.isScrollEnabled = true
categoriesVC.tableView!.isScrollEnabled = true
shopsVC.tableView!.isScrollEnabled = true
}
print("down")
}
but this solution has a some cons... and one of the is that first when child scrollview is at top or button, there should be two try to call my parent scrollview handle the scrolling, in first try i disable the child scrollview, and in second try parent scrollview handle the scrolling
** how can i say when you , my child, scrolling up, check if your parent is at top, then let him handle the scroll and when he touching the bottom, you can handle remain up scrolling, or tell the parent scrollview , if you are at top (user info is visible) if you or your child getting up scrolling, first you handle the scroll and when you rich at bottom(user info is not visible), let the remain scrolling on you child**
After a long long investigation that is how i achieve the twitter profile behaviour.
UnderlayScrollView
MasterScrollView
Header ViewController
Bottom ViewController
PagerTabItems [CollectionView]
UIPagerController or any other horizontal scroll (Parchment, XLPagerTabStrip).
UnderlayScrollView is responsible of controlling the scroll gesture. its contentoffset is used to adjust inner scroll contentOffsets. Contentsize of the underlaying scroll is same as the masterscroll's contentsize.
See the source code on github for more. click
I believe you are mostly right, except for the topmost scroll view.
In a recent app, I implemented something similar following this tutorial:
Basically, the trick is to have a class be the scrolling delegate of the bottom UITableViews, listen to the scrollViewDidScroll modifications, and modify the top inset of the UITableView and the TopView.
The structure I would use is like this:
Topview
ScrollView (horizontal scroll)
Segmented Control
ScrollView (horizontal, paging scroll)
UITableView
UITableView
UITableView
UITableView
You are totally right in it being mind blowing. Looks so simple.
I found a library,
https://github.com/maxep/MXSegmentedPager
Its totally works fine
I need to disable horizontal scrolling to only the left in my collection view. I know disabling horizontal/vertical scrolling completely is easy, but how do I disable only left scrolling, while still allowing for scrolling to the right.
Situation:
I have a collection view with 40 cells. Only 1 cell is visible at a time--centered in the view, however, you can scroll to the right to see remaining cells. Every minute, a method is called that moves to the next cell (i.e. Cell A is centered in the view, and after a minute, Cell B is centered in the view). I want the user to see remaining cells, but not previous cells.
Here was my basic mindset of what I was trying, but haven't been able to get very far:
if (self.summaryCollectionView.contentOffset.y < 0) {
self.summaryCollectionView.scrollEnabled = NO;
} else {
self.summaryCollectionView.scrollEnabled = YES;
}
I have a requirement in which I need to have the following functionality -
1)I have a custom segmented control. In order to implement paging to the segmented control I have used horizontal scroll view. Each page has its own vertical scroll view.
Requirement
1)The image should hide as user scrolls up in the respective pages and should show down when user scrolls down in respective pages but keeping the custom segment always at the top of the screen when image is hidden irrespective of the individual page selection-
What I have tried so far -
1st Method
I tried putting the image as header of a table view.
Created a single section with one cell & gave the section header as the custom segment. And in the cell I placed the horizontal scroll view with the cell's height adjusted to cover all portion left out of the superview but it didn't work out as when I scroll the vertical scrolling of individual pages it was not in sync with the table view.
2nd Method
I tried setting the segment initially with a fixed distance from the top & I increased & decreased the constraint inside scrollViewDidScroll(). But it too didn't work as when the user scrolled rapidly ,the changing of constraint value didn't follow correctly.
So is there any other way to achieve the same ?
Please suggest as I can't make out what to do?
You add a tableView and your UIImage on top of it inside a scrollView. The tableView must have the same height & width than your scrollView. Then you disable the pan gesture of the scrollView :
self.scrollView.panGesture.active = false
Then you have to implement a custom scroll in scrollViewDidScroll' of yourtableView`'s delegate:
func scrollViewDidScroll(scrollView: UIScrollView) {
if self.scrollView.contentOffset.y <= 100 {
self.scrollView.contentOffset.y += scrollView.contentOffset.y
self.tableView.contentOffset.y = 0
} else {
// let the tableView scroll normally
}
}
Or, you can have a try with https://github.com/bryankeller/BLKFlexibleHeightBar ;)
It's a great component that can handle many type on animation in the header based on the position of a scrollView.
I've got a view that has 3 tableView's. One is the "Main Table View", and then I have an 'Answers Table View' and 'Percentage Table View'.
When the screens loads, the Main Table View occupies the top 95% of the screen. The bottom of the screen is a UIView containing 2 buttons. "Answers" and "Percentage".
The way it works, is if I click "Percentage" it changes the height of the Main Table View to 0, and gives that height to the Answers Table View. This animates the "Answers/Percentage" View to the top, and reveals either the Answers or Percentage TableView below it.
Here's an example:
As you can see, I click on "Percentage" which animates it up. If you click on "Percentage" again it animates it back down.
However, what I want to do is if the "Answers/Percentage" view is at the bottom of the View, and the user scrolls the Main Feed UP reaches the very end of the tableView's contents (not just the end, but the end and a little bit more), I want to animate it up like in the .gif.
Similarly, if the "Answers/Percentage" is at the top, and the user scrolls the lower "Answers Table View" down past a certain point where there is no more data above, it will completely animate.
Also, I do not ever want the "Answers/Percentage" view to be in the middle, and showing a tableview both top and bottom. All one, or the other, but not a bit of both. Which I have right now.
What I need to know is... how can I detect if the user has scrolled past the very top or very bottom of the table view +30 pixels for example, to initiate my animation?
You can use the contentOffset property of the table view.
if(tableView.contentOffset.y >= (tableView.contentSize.height - tableView.frame.size.height)) {
// Start the animation
}
I haven't tested this, but let me know if it works.
Making another answer based on sublimepremise's approach because it's easier to format and post code that way. The base idea is to check the table view's .contentOffset.y, e.g. by implementing scrollViewDidScroll in its delegate, and triggering your animations accordingly.
It may have a bit of a QnD feel to it, but if you need to also abort the user's dragging action when triggering the animation, an easy way to do so would be by "resetting" the table view's gesture recognizer. In code that could look something like this:
static const CGFloat kChrisTableViewAnimationThreshold = 30.0f;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == self.topTableView) {
if([self scrolledPastBottomThresholdInTableView:self.topTableView]) {
// Start the animation
// ...
// Toggling the table view's pangGestureRecognizer off and on cancels the gesture
self.topTableView.panGestureRecognizer.enabled = NO;
self.topTableView.panGestureRecognizer.enabled = YES;
}
}
}
- (BOOL)scrolledPastBottomThresholdInTableView:(UITableView *)tableView {
return (tableView.contentOffset.y - kChrisTableViewAnimationThreshold >= (tableView.contentSize.height - tableView.frame.size.height));
}
Note that this illustration obviously only covers recognizing when the top table view is scrolled past its bottom end, but adapting it for handling other scenarios should be pretty straightforward.
I have added a UICollectionView which will have 5 cells, scrolling horizontally. I would like the user to be able to scroll between the cells, where each cell will snap to the centre. Here is a my UICollectionFlowLayout code used with the cell sizes etc.
-(UICollectionViewFlowLayout*)collectionLayout{
if (!_collectionLayout) {
_collectionLayout = [[UICollectionViewFlowLayout alloc]init];
_collectionLayout.minimumInteritemSpacing = 0;
_collectionLayout.minimumLineSpacing = 30;
_collectionLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_collectionLayout.itemSize = CGSizeMake(200, 165);
_collectionLayout.sectionInset = UIEdgeInsetsMake(0, 65, 0, 55);
_collectionLayout.collectionView.pagingEnabled = YES;
}
return _collectionLayout;
}
I have added insets so the first and last cell stops in the middle, though any of the three cells in between don't. Please see attached screen-shots to illustrate -[2 screen shots below]
I can easily achieve centralised paging of the cells if they are the width of the screen or I simply make 5 sections, however if I do this, then the user does not see the other cells left or right, which I need so they know there is more to scroll to, if you know what I mean.
I have read similar answers about disabling paging and using scrollViewWillEndDragging methods, but I could not get these to work either.
If anyone can offer any clear way to do this that would be great,
Thanks in advance
Jim
This likely won't be the solution you're ideally looking for, though it's an option you can use, as I have used for the set up you describe.
Increase your Uicollectionviewcell size to the width of the screen, with your purple square as view centralised within the cell. Remove your section inset code and change line spacing to =0.
At the left and right sides of the cell place arrow images (or as button), or a swipe gesture icon so app user knows there's more. As you've only got 5 cells, have cell at IndexPath.row==0 and IndexPath.row==4 to hide their left and right 'more' arrows respectively.