I have a tableview which has load more. I'd like to add scroll to top function when user press tabbar item twice like twitter, instagram.
This is my code when user tap twice to tab bar item.
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if previousController == viewController {
if let navVC = viewController as? UINavigationController, let vc = navVC.viewControllers.first as? AssistantMainViewController {
if vc.isViewLoaded && (vc.view.window != nil) {
// viewController is visible
vc.tableView.setContentOffset(CGPoint(x: 0, y: -173), animated: true)
}
}
}
previousController = viewController
}
It works fine when tableview first load. The problem is when I load more cell to my tableview and scroll to top, tableview not scrolls to top it stuck in middle of somewhere. Other weird thing is if I scroll manually to top after load more, tab bar item scroll tableview properly until load more cells.
In load more action basicly app get more content from server and add them to array and call tableview.reloadData()
adviceDataSource.loadMoreContent(beforeDay: beforeDate, success: {feedCount in
if feedCount == 0 {
self.didGetLastPage = true
}
self.tableView.reloadData()
self.tableView.layoutSubviews()
self.isRunningRequest = false
}, error: { (errorString, statusCode) in
self.isRunningRequest = false
}) { (MoyaError) in
self.isRunningRequest = false
}
Probably the problem is when I load more cell tableview doesn't know its new content size.By the way when tap status bar tableview scroll to top perfectly. If you know the func that called when user tap status bar, it would be perfect for me.
I've been working and searching on it 2 days, any help?
Thank you!
call UITabBarControllerDelegate in your viewcontroller tableView class.
in viewdidload Method call
self.tabBarController?.delegate = self
implement tab bar didselect in your viewcontroller class
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 0 {
self.tableView.setContentOffset(CGPoint.zero, animated: true)
}
}
Replace tableView.layoutSubviews() with tableView.layoutIfNeeded(), it layout the tableview immediately.
And use the tabbarcontrollerdelegate:
The viewcontroller(which owns the tableview) will listen to it. and use this method
self.primaryTableView.scrollToRow(at: IndexPath, at: UITableViewScrollPosition, animated: Bool)
Related
I want to implement a scrollToTop method on all of my viewControllers in my UITabBarController. The following is a method in the UITabBarControllerDelegate and triggers, when I select a tab.
The problem is, that I only want to scroll to the top of the viewController, when the viewController is active. So that the user can switch tabs without losing the scroll position, but when he touches the tab in the tabBar of the currently active tab, it should scroll to the top.
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if viewControllerThatIsCurrentlyActiveInTabBar == viewController {
scrollToTop()
}
}
Basically, I need that condition of the if statement above.
I tried: viewController.isViewLoaded, tabBarController.selectedViewController == viewController, viewController.isBeingPresented. None of those conditions worked. It would either not trigger scrollToTop() or it would trigger always so that you lose the scroll position when you change tabs because it would immediately scroll to the top.
You need to make a code in should select instead of didselect. As it is unable to find the previous controller after selection. below is the example code for it.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if tabBarController.selectedViewController == viewController {
print("Same viewcontroller")
}
return true
}
Can you use below extension for getting top viewcontroller of tabbarcontroller.
extension UIViewController {
var top: UIViewController? {
if let controller = self as? UINavigationController {
return controller.topViewController?.top
}
if let controller = self as? UISplitViewController {
return controller.viewControllers.last?.top
}
if let controller = self as? UITabBarController {
return controller.selectedViewController?.top
}
if let controller = presentedViewController {
return controller.top
}
return self
}
}
You can use above extension below
if let rootViewController = UIApplication.top() {
//do with Active view controller
}
I need to scroll to the top when I tapped second time to the first BarButtonItem (Home). There are a lot of answers but none of them don't work for me. It's incredible but it is.
I have UITabBarControllerDelegate in my class, self.tabBarController?.delegate = self in viewDidLoad() and this in my TableViewController:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if self.tabBarController?.selectedIndex == 0 {
self.tableView.setContentOffset(CGPoint(x: 0, y: -60), animated: true)
}
}
It works everytime I tapped to the Home (index = 0), but I need to do this when I'm already on the Home screen (standart function for all social media to scroll to the top Feed by tapping Home). And how to set Y coordinate if I have a NavigationBar above?
Thanks
All you have to do is check if selected viewController is your view controller that has tableView you need to scroll to top. Now I'd recommend using scroll to instead of setting content offset because that may vary based on the device and other logic (like large title for example)
Considering you have your custom tab bar controller that has all the tabs references you could do something like this:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if viewController == myViewController {
myViewController.tableView.scrollToRow(
at: IndexPath(row: 0, section: 0),
at: .top,
animated: true)
}
}
}
I using TableView under Tab Bar
My requirement is to scroll table view up when user double tap on tab bar item for selected view controller
this is my code
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool
{
if tabBarController.viewControllers!.index(of: viewController) == 0 {
if let navigationController = viewController as? UINavigationController{
if let streamController = navigationController.viewControllers.last as? StreamViewController
{
streamController.tableViewStream.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
}
}
return true
}
}
But this is causing to scroll table up when user even single tap on item, due to this I am note able to retain scroll position.
So what I want is
1.If user scroll the table and go on another tab and come back again by single tap scroll position should remain same
2.If user tap double any time on tab tab bar item the list should be scroll to top
In your code i would add checking if this view controller is already selected
if tabBarController.viewControllers!.index(of: viewController) == 0 {
if self.selectedIndex != 0 { return true }
if let navigationController = viewController as? UINavigationController{
if let streamController = navigationController.viewControllers.last as? StreamViewController
{
streamController.tableViewStream.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
}
}
return true
}
I want to scroll to the top when i double tap on any BarButtonItem.
I saw a lot of answers on stackOverflow but none of them worked for me.
Maybe I'm using it wrong? Where do i put the code in the AppDelegate or the TableViewControllers i want to add this functionality specifically?
anyway, I'm using Swift 2.3 and Xcode 8 and would love to get some help.
Thank you.
Do you know about scrollsToTop? I think it is what you need. Description from iOS SDK related to scrollsToTop property in UIScrollView:
When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its scrollsToTop property is YES, its delegate does not return NO from shouldScrollViewScrollToTop, and it is not already at the top.
// On iPhone, we execute this gesture only if there's one on-screen scroll view with scrollsToTop == YES. If more than one is found, none will be scrolled.
At first setup UITabBarControllerDelegate delegate. Delegate can be easily set from Storyboard or via code with UITabBarController's delegate property.
myTabBar.delegate = myNewDelegate // Have to conform to UITabBarControllerDelegate protocol
You can even subclass UITabBarController and implement UITabBarControllerDelegate for it so it can become delegate for itself.
mySubclassedTabBar.delegate = mySubclassedTabBar
When you have delegate you can try out this method.
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool
{
guard let tabBarControllers = tabBarController.viewControllers
else
{
// TabBar have no configured controllers
return true
}
if let newIndex = tabBarControllers.indexOf(viewController) where newIndex == tabBarController.selectedIndex
{
// Index won't change so we can scroll
guard let tableViewController = viewController as? UITableViewController // Or any other condition
else
{
// We are not in UITableViewController
return true
}
tableViewController.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: true)
}
return true
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if tabBarController.viewControllers!.firstIndex(of: viewController) == 0 {
if self.selectedIndex != 0 { return true }
if let navigationController = viewController as? UINavigationController{
if let streamController = navigationController.viewControllers.last as? HomeVC
{
streamController.tableView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
}
}
return true
}
return true
}
I am trying to implement a UIPageViewController, where you can slide between two UICollectionViewControllers (much like the iOS 8.4 music App). This is also supposed to use one instance of UINavigationController.
This is what I've tried so far:
Using Storyboard, I've added a new PageViewController, in which I have conformed to the UIPageViewControllerDataSource as well as the UIPageViewControllerDelegate protocols.
Using Storyboard identifiers, I have successfully been able to get this to the point where you can swipe between each view.
Here is some sample code to be more specific:
override func viewDidLoad() {
self.dataSource = self
self.delegate = self
let startingViewController = self.viewControllerAtIndex(index)
let viewControllers: NSArray = [startingViewController]
self.setViewControllers(viewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
func viewControllerAtIndex(index: Int) -> UICollectionViewController! {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
if index == 0 {
return storyBoard.instantiateViewControllerWithIdentifier("AlbumsController") as! UICollectionViewController
}
if index == 1 {
return storyBoard.instantiateViewControllerWithIdentifier("SubscriptionsController") as! UICollectionViewController
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let identifier = viewController.restorationIdentifier
let index = self.identifiers.indexOfObject(identifier!)
if index == identifiers.count - 1 {
return nil
}
self.index = self.index + 1
return self.viewControllerAtIndex(self.index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let identifier = viewController.restorationIdentifier
let index = self.identifiers.indexOfObject(identifier!)
if index == 0 {
return nil
}
self.index = self.index - 1
return self.viewControllerAtIndex(self.index)
}
The problem arises in the gestures being lost/overwritten when swiped to the next view. Initially I can scroll the first collection view and tap on the status bar to scroll to the top, but as soon as the pageviewcontroller swipes over to the next collection view, this gesture stops working and now neither collection view responds to the "scroll to top" gesture.
I have also heard using a scrollview is possible, but I wasn't convinced that this implementation would be more appropriate that using a UIPageViewController.
Current research suggests that the gestures are affected by the 'data source' of the PageViewController and must be altered in some way.
I have also embedded the UIPageViewController inside of a UINavigationController to achieve a shared navigation bar for both views. Now of course the navigation bar overlaps the UICollectionViews as they are not themselves embedded within a UINavigationController. To work my way around this problem, I've used this code below:
collectionView.contentInset = UIEdgeInsets(top: 64, left: 0, bottom: 0, right: 0)
Would anyone be able to give me some advice on how to properly re-create the 'swiping between two views' effect you get in the new Music App?
With my current implementation, I feel as it is not the correct way to achieve my goal, so I would greatly appreciate any help.