My goal is basically to create a tableView with paging enabled that uses sections to determine the amount of pages, and which page you're on.
Example: 3 sections
1 section: 3 cells
2nd section: 14 cells - Scrolls to the very bottom of the section as a normal tableView would, when it hits the bottom, if you user continues swiping, goes to next page.
3rd section: 8 cells - Scrolls to bottom and stops.
So the first page would have 3 cells, then blank space, if you started to scroll up then the next section would appear, then that section header would snap to the top and you will have changed pages
The second page has many cells more than can fit on a single screen at one time, the user scrolls to the bottom of these, once the bottom is reached, can continue to scroll to reveal the third section header, then that header will snap to the top, etc
I know how to create a pages tableView, it is the paging out the tableview using sections rather than view height that I do not know is possible
I had to do something similar to your design.
I needed the first section to take up the entre screen and the second one to be an infinite scroll, with paging between Section 1 and Section 2 when scrolling down. Also, when scrolling up, I wanted the scroll to stop before the top section.
I know it is slightly different to your case, but you could quite easily figure out the height of each section and apply it similarly to my design.
here is how I did it :
func scrollViewDidScroll(scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
if (lastContentOffset > offsetY) {
tableNode.view.pagingEnabled = offsetY < view.frame.height
}
lastContentOffset = offsetY
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
tableNode.view.pagingEnabled = offsetY < view.frame.height
}
Note that the scrollViewDidEndDecelerating is important to re-enable paging when scrolling DOWN.
Also notice I am only setting the tableNode.view.pagingEnabled when the user scrolls UP in the scrollViewDidScroll function.
Hope this helps anyone looking for this in the future, as I hope for you #YichenBman you have come up with a solution by now.
Related
Almost everyone can find examples with infinite collectionView load more data when collectionView scrolls to bottom, but maybe anybody known how infinite scroll collectionView from bottom to top?
Like a chat history load more when user scrolls up.
For example.
I have a list with 100000 items and with one of conditions. The app should show to a user items from 9500 to 9600 and when user scrolls up, the app should add to the collectionView items from 9400 to 9500 at the begin of collectionView, and when user scrolls down - the app should add to the collectionView to the end of collectionView and etc.
I've googled and have tried reverse logic for bottom infinite collectionView, but it unsuccessful.
CollectionView just scrolled up to the first item on the list.
Any ideas or tips?
The result you are describing is expected. Since you scrolled to top the content offset is at zero. And when you added new items the old ones were pushed to the bottom. It will not happen the other way around; when you scroll to bottom and add items beneath them the scroll position stays the same.
To be honest it is all about perspective. The position actually stays the same in both cases (or none) but depends on how you look at it. When you append items at bottom the position should stay the same looking from top (which is a default scenario). But when you add items at top the position stays the same from bottom.
So the solution in your case is that when you add items at the bottom you should change scroll from top:
let distanceFromTop = scrollView.contentOffset.y - 0.0;
// Reload data here
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: 0.0 + distanceFromTop)
which basically means "do nothing at all".
But when you are appending items at the top you need to compute it from bottom:
let distanceFromBottom = scrollView.contentSize.height - scrollView.contentOffset.y;
// Reload data here
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: scrollView.contentSize.height - distanceFromBottom)
You should note that you can do this sideways as well. Appending items on the right side would again be transparent. But adding them on the left should be like:
let distanceFromRight = scrollView.contentSize.width - scrollView.contentOffset.x;
// Reload data here
scrollView.contentOffset = CGPoint(x: scrollView.contentSize.width - distanceFromRight, y: scrollView.contentOffset.y)
I am using scrollView as this happens the same to every subclass of it. The same logic can be applied to table view or collection view.
Another note here is that estimated row heights or similar functionalities may cause anomalies when not done correctly. In such cases you may need to compute the offset a bit more smartly.
I am developing a chat conversation UI using UICollectionViewController, initially having 20 items in collectionViewController.
When I did scroll to top.
if scrollView.contentOffset.y == - 44 { /* Inserting 10 items at zero th position in collectionView */ }
I will insert 10 items at IndexPath(item: 0, section: 0)
So will have a total of 30 items in CollectionView.
At this time I got some UI animation issue and collection view was scrolled to top.
e.g actual items are 0,1,2,3...19
now I am inserting at zeroth index so items like 29,28,27,...20,0,1,2,3...19
I hope you understand.
my issue is when my collection view is showing 0,1,2,3 at top I am inserting 29,28,27,...20
but collection view won't scroll to up or down. It has to show same 0,1,2,3 like (silently insert items at top and don't change any ui)
Like WhatsApp chat - fetching old messages while scrolling to top.
I don't know if I understand, but you can try this:
self.collectionView.setContentOffset(CGPoint(x:0,y:0), animated: true)
after your insertItem method populate your datasource.
So heres my issue, the 4 orange rectangles you see on the gif are a single vertical UICollectionView = orangeCollectionView.
The Green and Purple "card" views are part of another UICollectionView = overlayCollectionView.
overlayCollectionView has 3 cells, one of which is just a blank UICollectionViewCell, the other 2 are the cards.
When the overlayCollectionView is showing the blank UICollectionViewCell, I want to be able to scroll the orangeCollectionView.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
guard let superr = superview else { return true}
for view in superr.subviews {
if view.isKind(of: OrangeCollectionView.self) {
view.point(inside: point, with: event)
return false
}
}
return true
}
This allows me to scroll the orangeCollectionView HOWEVER this doesn't actually work to fix my issue. I need to be able to scroll left and right to show the cards, however this blocks all touches becuase the point always falls on the OrangeCollectionView.
How can I check to see if they are scrolling left/right to show the cards? Otherwise if they are on the blank cell, scroll the orangeViewController up and down.
Had this issue as well... Didn't find a nice way to do it, but this works.
First, you need to access the scroll view delegate method scrollViewDidScroll(). There you call:
if scrollView == overlayScrollView {
if scrollView.contentOffset.x == self.view.frame.width { // don't know which coordinate you need
self.overlayScrollView.alpa = 0
}
}
After that, you add a blank view onto of the orange collection view. The view's alpha is 0 (I think, maybe the color is just clear; try it out if it works).
In the code, you then add a UISwipeGestureRecognizer to the view you just created and and detect whether there's a swipe to the left or to the right.
By detecting the direction of that swipe, you can simply change the contentOffset.x axis of your overlayScrollView to 0 or self.view.frame.width * 2.
Sorry I can't provide my working sample code, I'm answering from my mobile. It's not the proper solution, but when I made a food app for a big client it worked perfectly and no one ever complained :)
I have this table view which in some cases contains few rows, even one.
What’s wrong with it is that even if I have one row, it allows me to scroll down and the row gets hidden at top.
It practically almost disappears from screen, as if there would be somethingto show below it.
I can’t disable scrolling because I have pull down to refresh.
Any ideas if there is a setting I am missing? Or how I could not allow scroll down if I do not have enough rows to cover the whole screen?
Actually, your case is kind of tricky, because:
The first I thought that the solution will be myTableView.alwaysBounceVertical = false
That's will do the job for you, but the problem in your case that you have a UIRefreshControl() and setting alwaysBounceVertical to false will disable scrolling to top for displaying the refreshController.
So, it should be done manually, as follows:
1- Implement the scrollViewDidScroll method from UIScrollViewDelegate.
2- check the scrolling direction in it.
3- if the scrolling direction goes down, check if content size of the tableView is more than its height, i.e check if tableView contains cell more than its height.
4- if the output of step 3 is false, disable scrolling, else, enable scrolling.
5- add dispatch_after to re-enable tableView scrolling.
It goes like this (Note: Swift 2 code.):
private var lastContentOffset: CGFloat = 0
// 1
func scrollViewDidScroll(scrollView: UIScrollView) {
// 2
if (self.lastContentOffset > scrollView.contentOffset.y) {
print("scrolling up")
}
else if (self.lastContentOffset < scrollView.contentOffset.y) {
print("scrolling down")
// 3 and 4
myTableView.scrollEnabled = myTableView.contentSize.height > myTableView.frame.size.height ? true : false
// 5
// delaying is half a second
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_MSEC) * 500), dispatch_get_main_queue(), { () -> Void in
self.myTableView.scrollEnabled = true
})
}
}
Hope this is a good solution for your case.
I have a collectionview with a grid of cells that is 3 wide by 3 tall. I have paging enabled to scroll horizontally to see the next page of 9 cells. However, I don't have a full 9 cells for the last page, only 3 remaining cells. The paging only scrolls to the first column of cells and it looks bad. I want it to scroll fully to the third page so it displays the 3 remaining cells in the first column and and 6 empty ones in the second 2 columns. Any help is greatly appreciated! Here is the paging code I have, thanks in advance!
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
// sets which page we are currently on
let pageWidth:CGFloat = collectionView.frame.size.width
let currentPage:CGFloat = collectionView.contentOffset.x / pageWidth
// sets the page control to the current page
pageControl.currentPage = Int(currentPage)
}
When you get the Collection that would be displayed in your CollectionView you should do a modulo on it by 9 to get the remainder. If the modulo is 0, do nothing. If the modulo is any other number, subtract that number from 9 and add that many "dummy" cells to your collection to fill them out.
Here is some code to get you started:
int remainder = (int)[self.collectionView numberOfItemsInSection:0] % 9; //I am assuming you don't have more than one section
if(remainder){
for(i = 9; i > remainder; i--){
//add a dummy item to collectionView
}
}