0

So I have a view controller with a collection view containing two collection view cells in numberOfItemsInSection. There is a tableview in each of the cells. I'm trying to go to the top of the tableview when my certain tab bar item is clicked. My problem is that I can't access the tab bar in my collection view cell and when I access the tab bar in my view controller and call a function in my collection view cell from the view controller it doesn't work (it says I don't have any rows in my tableview).

Here's me setting up the collection view in my view controller and trying to send the collection view cell's tableview to the top when calling func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) in my view controller.

class AllPostsVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITabBarControllerDelegate {
   var indexPath:IndexPath?

   override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()       
        self.tabBarController?.delegate = self
    }

    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.dataSource = self
        cv.delegate = self
        return cv
    }()

    func setupCollectionView() {
        
        view.addSubview(collectionView)
        
        view.bringSubviewToFront(collectionView)
        
        collectionView.isPagingEnabled = true
        
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor).isActive = true
        collectionView.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor).isActive = true
        
        collectionView.topAnchor.constraint(equalTo: self.menuBar.bottomAnchor).isActive = true
        
        collectionView.register(AllPostsCell.self, forCellWithReuseIdentifier: cellId)
        collectionView.register(AllPostsUnderReviewCell.self, forCellWithReuseIdentifier: postsUnderReviewcell)        
        
    }
    

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        for cell in collectionView.visibleCells {
              indexPath = collectionView.indexPath(for: cell)
            print(indexPath)
        }
    }


    func scrollToMenuIndex(menuIndex: Int) {
        let indexPath = NSIndexPath(item: menuIndex, section: 0)
        collectionView.scrollToItem(at: indexPath as IndexPath, at: [], animated: true)
    }

    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {

        if tabBarIndex == 0 {
            if indexPath?.item == 0 {
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath!) as! AllPostsCell
                cell.sendToTop()
            }
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 2
    }

     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     
        var albumsCell:UICollectionViewCell?
        
        if indexPath.item == 1 {
            let underReviewCell = collectionView.dequeueReusableCell(withReuseIdentifier: postsUnderReviewcell, for: indexPath) as! AllPostsUnderReviewCell
                underReviewCell.parent = self
                return underReviewCell
        }
        
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! AllPostsCell
         cell.parent = self
         return cell
  
        
    }

In my Collection View Cell

class AllPostsCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {
    func sendToTop() {
        DispatchQueue.main.async {
            self.layoutIfNeeded()
            self.myTableView.layoutIfNeeded()
            let indexPath = NSIndexPath(row: 0, section: 0)
            self.myTableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
        }
    }
}

When I do this I get the error: Terminating app due to uncaught exception 'NSRangeException', reason: 'Attempted to scroll the table view to an out-of-bounds row (0) when there are only 0 rows in section 0. even when I see rows in my table view. Although it does call my collection view cell's init method again.

So what's a good solution to send my tableview to the top, in my collection view cell, when I click on my certain tab bar item?

DDavis25
  • 1,149
  • 1
  • 13
  • 25

1 Answers1

1

Solution: I had to send a Notification from my View Controller to my Collection view cell once the right tab bar index was clicked.

Get the index of the collection view cell in my view controller.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        menuBar.horizontalBarLeftAnchorConstraint?.constant = scrollView.contentOffset.x / 2
        let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
            let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
            indexPath = collectionView.indexPathForItem(at: visiblePoint)
    }

Send the Notification from the view controller to the certain collection view cell once the certain tab bar item was clicked.

func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {

        let tabBarIndex = tabBarController.selectedIndex

        if tabBarIndex == 0 {
            if indexPath?.item == 0 {
                NotificationCenter.default.post(name: Notification.Name("sendToTop"), object: nil)
            } else if indexPath?.item == 1 {
                NotificationCenter.default.post(name: Notification.Name("sendToTopUR"), object: nil)
                
            }
        }
    }

Collection View Cell at index 0

override init(frame: CGRect) {
        super.init(frame: frame)
   NotificationCenter.default.addObserver(self, selector: #selector(sendToTop), name: NSNotification.Name(rawValue: "sendToTop"), object: nil)
}

@objc func sendToTop() {
        DispatchQueue.main.async {
            self.layoutIfNeeded()
            self.myTableView.layoutIfNeeded()
            let indexPath = NSIndexPath(row: 0, section: 0)
            self.myTableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
        }
    }
DDavis25
  • 1,149
  • 1
  • 13
  • 25