I created a horizontal tableView, with cells that take up the whole view controller. Instead of scrolling with the default setting, I would like to scroll to the next cell using scrollView.scrollToItem(at: IndexPath method.
Meaning, each time the user scrolls right, it will automatically scroll to the next cell, and each time the user swipes left, it will automatically scroll to the previous cell. Whenever you scroll a direction, it should automatically scroll to the next or previous cell.
I tried intercepting it using scrollViewDidScroll delegate method, but I am running into a ton of problems, it is autoscrolling back and forth and glitching a ton. What am I doing wrong?
var previousOffset: CGFloat = 0.0
var allowHorizontalScroll: Bool = true
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (allowHorizontalScroll){
let offset = scrollView.contentOffset.x
let diff = previousOffset - offset
previousOffset = offset
var currentBoardIndex = scrollView.indexPathForItem(at: CGPoint(x:offset, y:10))?.item
if currentBoardIndex != nil {
if diff > 0 {
//print("scroll left")
if (currentBoardIndex != 0){
currentBoardIndex = currentBoardIndex! - 1
allowHorizontalScroll = false
scrollView.scrollToItem(at: IndexPath(row: (currentBoardIndex!), section: 0), at: .left, animated: true)
}
}else{
//print("scroll right")
if (currentBoardIndex != ((boardVCDataSource?.fetchedResultsController.fetchedObjects?.count)! - 1)){
currentBoardIndex = currentBoardIndex! + 1
allowHorizontalScroll = false
scrollView.scrollToItem(at: IndexPath(row: (currentBoardIndex!), section: 0), at: .left, animated: true)
}
}
}
}
}
Whenever you scroll a direction, it should automatically scroll to the next or previous cell.
Why not throw out all that code, and instead set your scroll view's isPagingEnabled to true? A paging scroll view does what you describe, automatically.
Related
I have segmented control as a header of UITableView with cell names. Tableview has different cells with different sizes. When I tap on segment, I do a scroll to specific row in a tableview.
segment.valueSelected = { index in
self.contentTableView.scrollToRow(at: IndexPath(row: index, section: 1), at: .top, animated: true)
}
But how can I change selected index of segmented control when I scroll my tableview? I mean I know how to change index, but the problem is how can I calculate specific offset since all cells has different sizes?
func scrollViewDidScroll(_ scrollView: UIScrollView) {
segment.setSelectIndex(index : ???)
}
Solved by
let visiblerows = contentTableView.indexPathsForVisibleRows
if let lastIndex = visiblerows?.last {
segment.setSelectIndex(index: lastIndex.row, animated: true)
}
There are two scrollView in the View: mainScrollView(red) and listTable(yellow). I want to set that mainScrollView scrolls first and does the following actions:
When the topView disappears and top of the listTable reaches top of the screen, the listTable scrolls up automatically.
If the top of listTable is at the top of screen, the mainScrollView scroll down first when user scrolls down.
func detectScrollView(_ scrollView: UIScrollView){
if scrollView.tag == 1{
if scrollView.contentOffset.y >= 100{
mainScrollView.isScrollEnabled = false
mainScrollView.contentOffset.y = 100
mainScrollView.panGestureRecognizer.isEnabled = false
listTable.isScrollEnabled = true
listTable.panGestureRecognizer.isEnabled = true
}
}else{
//.....
}
}
By now, I just try the codes of scrolling up action, and it can runs part of my need. Problem is that the listTable cannot scrolls automatically when it's top reaches top of the screen. I have to make it works by releasing my finger from the screen and starting a new drag.
How can I continue the panGesture using on the listTable?
======= Update 2017-7-3 =======
I temporarily use the following codes:
var lastContentOffset:CGFloat = 0
func detectScrollView(){
if (self.lastContentOffset > mainScrollView.contentOffset.y) {
// move up
listTable.isScrollEnabled = true
}
else if (self.lastContentOffset < mainScrollView.contentOffset.y) {
// move down
if mainScrollView.contentOffset.y >= 110{
mainScrollView.setContentOffset(CGPoint(x:0, y:110), animated: true)
listTable.isScrollEnabled = true
}else{
listTable.isScrollEnabled = false
}
}
// update the new position acquired
self.lastContentOffset = mainScrollView.contentOffset.y
}
Moving up is solved, and still moving down needs retouching the screen so as to scroll the listTable.
When I drag section and move of UICollectionView using longPress Gesture then how to auto scroll UICollectionView's scrollview.
Note: in UICollectionView section 0 and 1 not scroll down, onward section only scrolling. 0 and 1 section set as sticky which is not scrolling when I move section.
UnTested Code:
Try this code inside your viewDidload or viewWillAppear.
let indexPath = NSIndexPath(forRow: 10, inSection: 0) // 1
self.collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: true)
Solved it.
func handleLongGesture(gesture: UILongPressGestureRecognizer) { //dragging Functionality handled here.
let point = gesture.locationInView(self.collectionView)
switch(gesture.state) {
case UIGestureRecognizerState.Changed:
let gesturePoint = gesture.locationInView(self.collectionView)
guard let changeIndexPath = self.collectionView.indexPathForItemAtPoint(gesturePoint)
where changeIndexPath.section > 1 else {
break
}
}
}
Is there a practice to scroll a collection view with cells, and, depending on its content offset, scroll the other collection view?
I have a main collection view that has two cells and scrolls horizontally. Then I have a second collection view with cells that scrolls vertically. What happens is when I scroll up, then scroll horizontally to the second vertical cv, it's not synced with relation to the first.
I overrode the scrollViewDidScroll inside the vertically scrolling collection view (not the main one, because it scrolls horizontally), to no avail (** means the parts that don't work to achieve my effect).
var didScrollPastProfileView: Bool = false
func scrollViewDidScroll(scrollView: UIScrollView) {
let collectionViewDictionary = ["scrollView": self.collectionView]
NSNotificationCenter.defaultCenter().postNotificationName("cvDidScroll", object: nil, userInfo: collectionViewDictionary)
if scrollView.contentOffset.y > 250 {
**self.didScrollPastProfileView = true
if self.didScrollPastProfileView {
let previousContentOffset = scrollView.contentOffset.y
scrollView.contentOffset.y = previousContentOffset
}**
} else if scrollView.contentOffset.y < 250 {
**let previousContentOffset = scrollView.contentOffset.y
scrollView.contentOffset.y = previousContentOffset
self.didScrollPastProfileView = false**
}
}
Here's a visual:
Notice how there's space above when I scroll to the second cell? I want that vertical scroll view to follow the first. Any suggestions?
EDIT: I tried to access the second cell of the horizontal collection view while I was scrolling in the first cell, and I tried to change contentOffSet.y when I scrolled down in the first one, but I got an EXC_BAD_ACCESS error.
if scrollView.contentOffset.y <= 250.0 {
let groupsPosts = childViewControllerForPosts.collectionView(childViewControllerForPosts.collectionView!, cellForItemAtIndexPath: NSIndexPath(forItem: 1, inSection: 0)) as! FeedCell
groupsPosts.collectionView.contentOffset.y = -scrollView.contentOffset.y
self.topVerticalConstraint?.constant = -scrollView.contentOffset.y
You can do something like this when scrolled to the collectionViewB with animated to false so it look like it is synchronised.
let indexPath = collectionViewA.indexPathsForVisibleItems().first
self.collectionViewB.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.Top, animated: false)
Not exactly sure how you set up this two collection. If you do not have access to collectionViewA then you might have to save the current indexPath to a variable and pass it over.
I used two collection views and they are connected to each other for scrolling. if one scroll the other one will scroll too.
this is handling in my didScroll delegate function as below:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
var screenHeight = max(Int(UIScreen.mainScreen().bounds.width), Int(UIScreen.mainScreen().bounds.height))
if ( collectionView == self.bottomSliderCollectionView)
{
return CGSizeMake(self.sliderCollectionView.frame.width - 65, 50)
}else {
return CGSizeMake(self.sliderCollectionView.frame.width , self.sliderCollectionView.frame.height)
}
}
func scrollViewDidScroll(scrollView: UIScrollView) {
if (scrollView == self.sliderCollectionView ){
// Calculate where the collection view should be at the right-hand end item
var contentOffsetWhenFullyScrolledRight = self.sliderCollectionView.frame.size.width * CGFloat(self.workingMenuSlider.count - 1)
if (scrollView.contentOffset.x == contentOffsetWhenFullyScrolledRight ) {
// user is scrolling to the right from the last item to the 'fake' item 1.
// reposition offset to show the 'real' item 1 at the left-hand end of the collection view
var newIndexPath = NSIndexPath(forItem: 1, inSection: 0)
self.sliderCollectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
} else if (scrollView.contentOffset.x == 0) {
// user is scrolling to the left from the first item to the fake 'item N'.
// reposition offset to show the 'real' item N at the right end end of the collection view
var newIndexPath = NSIndexPath(forItem: self.workingMenuSlider.count - 2, inSection: 0)
self.sliderCollectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
}
}
if (scrollView.contentOffset.x < 0) {
var newIndexPath = NSIndexPath(forItem: self.workingMenuSlider.count - 2, inSection: 0)
self.sliderCollectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
self.bottomSliderCollectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
}
var contentOffsetWhenFullyScrolledRight = self.sliderCollectionView.frame.size.width * CGFloat(self.workingMenuSlider.count - 1)
if (scrollView.contentOffset.x > contentOffsetWhenFullyScrolledRight) {
var newIndexPath = NSIndexPath(forItem: 1, inSection: 0)
self.sliderCollectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
self.bottomSliderCollectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
}
if (self.sepratedScroll == true ) {
if (scrollView == self.sliderCollectionView ){
var nesbat = (self.bottomSliderCollectionView.frame.width - 65) / self.sliderCollectionView.frame.width
self.sepratedScroll = false
self.bottomSliderCollectionView.contentOffset.x = self.sliderCollectionView.contentOffset.x * nesbat
self.sepratedScroll = true
}else {
self.sepratedScroll = false
var nesbat = (self.bottomSliderCollectionView.frame.width - 65) / self.sliderCollectionView.frame.width
self.sliderCollectionView.contentOffset.x = (self.bottomSliderCollectionView.contentOffset.x ) / nesbat
self.sepratedScroll = true
}
} else {
}
}
as you see var nesbat is calculating a float which is because my bottomCollection View cell width is - 65 than the sliderCollectionView.
both of them set to paging scroll. the top one (SliderCollectionView) works well. and it is an infinite scrolling which has the duplicate value in my array of data.
so, my question here is when my bottomCollectionview slides, which is a paging scroll, it goes more than its cell width.
i want to scroll exactly the width of the cell in bottomCollectionView.
i tested the answers which are saying to handle it on didScroll View but it is ok for my case. I have too many if to handle the infinite scrolling and also the connected collection views.
please help me with the paging scroll to set on the cells width not the width of the whole collectionView.
thankx
okay i got it myself.
i change my top collection view height and move it over the bottom collection view. but the content in xib for collection view bottom constraints changed to + 50 .
so i have a collection view on top with its content is - 50 than the height of the collection view and it is over the bottomCollectionView.
so i have the suer interaction of my top one .
problem solved :D :)