Tap tab bar to scroll to top of UITableViewController

后端 未结 12 933
面向向阳花
面向向阳花 2020-12-23 10:15

Tapping the tab bar icon for the current navigation controller already returns the user to the root view, but if they are scrolled way down, if they tap it again I want it t

相关标签:
12条回答
  • 2020-12-23 10:25

    I found the scrollRectToVisible method works better than the setContentOffset.

    Swift:

    After you catch the click on the tab bar from the delegate, something like below:

    func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
     if (viewController.isKindOfClass(SomeControllerClass) && tabBarController.selectedIndex == 0) 
          {
            viewController.scrollToTop()
          }
     }
    

    Now for the scrollToTop function inside the controller:

    func scrollToTop()
    {
        self.tableView.scrollRectToVisible(CGRectMake(0,0,CGRectGetWidth(self.tableView.frame), CGRectGetHeight(self.tableView.frame)), animated: true)
    } 
    
    0 讨论(0)
  • 2020-12-23 10:26

    Implement the UITabBarControllerDelegate method tabBarController:didSelectViewController: to be notified when the user selects a tab. This method is also called when the same tab button is tapped again, even if that tab is already selected.

    A good place to implement this delegate would probably be your AppDelegate. Or the object that logically "owns" the tab bar controller.

    I would declare and implement a method that can be called on your view controllers to scroll the UICollectionView.

    - (void)tabBarController:(UITabBarController *)tabBarController 
     didSelectViewController:(UIViewController *)viewController
    {
        static UIViewController *previousController = nil;
        if (previousController == viewController) {
            // the same tab was tapped a second time
            if ([viewController respondsToSelector:@selector(scrollToTop)]) {
                [viewController scrollToTop];
            }
        }
        previousController = viewController;
    }
    
    0 讨论(0)
  • 2020-12-23 10:26

    SWIFT 3

    Here goes..

    First implement the UITabBarControllerDelegate in the class and make sure the delegate is set in viewDidLoad

    class DesignStoryStreamVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITabBarControllerDelegate {
    
     @IBOutlet weak var collectionView: UICollectionView!
    
     override func viewDidLoad() {
            super.viewDidLoad()
    
            self.tabBarController?.delegate = self
    
            collectionView.delegate = self
            collectionView.dataSource = self
        }
    }
    

    Next, put this delegate function somewhere in your class.

    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
    
        let tabBarIndex = tabBarController.selectedIndex
    
        print(tabBarIndex)
    
        if tabBarIndex == 0 {
            self.collectionView.setContentOffset(CGPoint.zero, animated: true)
        }
    }
    

    Make sure to select the correct index in the "if" statement. I included the print function so you can double check.

    0 讨论(0)
  • 2020-12-23 10:28

    In this implementation you no need static variable and previous view controller state

    If your UITableViewController in UINavigationController you can implement protocol and function:

    protocol ScrollableToTop {
        func scrollToTop()
    }
    
    extension UIScrollView {
        func scrollToTop(_ animated: Bool) {
            var topContentOffset: CGPoint
            if #available(iOS 11.0, *) {
                topContentOffset = CGPoint(x: -safeAreaInsets.left, y: -safeAreaInsets.top)
            } else {
                topContentOffset = CGPoint(x: -contentInset.left, y: -contentInset.top)
            }
            setContentOffset(topContentOffset, animated: animated)
        }
    }
    

    Then in your UITableViewController:

    class MyTableViewController: UITableViewController: ScrollableToTop {
       func scrollToTop() {
        if isViewLoaded {
            tableView.scrollToTop(true)
        }
       }
    }
    

    Then in UITabBarControllerDelegate:

    extension MyTabBarController: UITabBarControllerDelegate {
        func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
            guard tabBarController.selectedViewController === viewController else { return true }
            guard let navigationController = viewController as? UINavigationController else {
                assertionFailure()
                return true
            }
            guard
                navigationController.viewControllers.count <= 1,
                let destinationViewController = navigationController.viewControllers.first as? ScrollableToTop
            else {
                return true
            }
            destinationViewController.scrollToTop()
            return false
        }
    }
    
    0 讨论(0)
  • 2020-12-23 10:33

    I have a collection view embedded in a navigation controller, in Swift this works.

    var previousController: UIViewController?
    
    func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
        if previousController == viewController {
            if let navVC = viewController as? UINavigationController, vc = navVC.viewControllers.first as? UICollectionViewController {
                vc.collectionView?.setContentOffset(CGPointZero, animated: true)
            }
        }
        previousController = viewController;
    }
    
    0 讨论(0)
  • 2020-12-23 10:37

    Swift 5: no need for stored properties in the UITabBarController.

    In MyTabBarController.swift, implement tabBarController(_:shouldSelect) to detect when the user re-selects the tab bar item:

    protocol TabBarReselectHandling {
        func handleReselect()
    }
    
    class MyTabBarController: UITabBarController, UITabBarControllerDelegate {
        override func viewDidLoad() {
            super.viewDidLoad()
            delegate = self
        }
    
        func tabBarController(
            _ tabBarController: UITabBarController,
            shouldSelect viewController: UIViewController
        ) -> Bool {
            if tabBarController.selectedViewController === viewController,
                let handler = viewController as? TabBarReselectHandling {
                // NOTE: viewController in line above might be a UINavigationController,
                // in which case you need to access its contents
                handler.handleReselect()
            }
    
            return true
        }
    }
    

    In MyTableViewController.swift, handle the re-selection by scrolling the table view to the top:

    class MyTableViewController: UITableViewController, TabBarReselectHandling {
        func handleReselect() {
            tableView?.setContentOffset(.zero, animated: true)
        }
    }
    

    Now you can easily extend this to other tabs by just implementing TabBarReselectHandling.

    0 讨论(0)
提交回复
热议问题