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
}
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 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)
I have this scenario:
Both view 1 and view 2 transitions to final view.
Now, here comes the problem.
When I transition from view 1 to final view, then I tap item 2, it transitions to view 2. But then I tap item 1, it transitions to final view. This is because view 1 was transitioned to final view awhile ago.
So, is there anyway that I could always show view 1 when item1 is tapped?
Well you should try it:
class FinalViewController:UIViewController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController,didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 0 {
_ = self.navigationController?.popViewController(animated: true)
}else{
//whatever
}
}
}
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
}
Because I want to redesign the tab bar UI, I wrote a custom tab bar controller according to https://github.com/codepath/ios_guides/wiki/Creating-a-Custom-Tab-Bar
In TabBarViewController's viewDidLoad(), define several subviews corresponding to each tab bar
homeViewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
...
viewControllers = [homeViewController, searchViewController, accountViewController, trendingViewController]
and the main method when tapping tab
#IBAction func didPressTab(_ sender: UIButton) {
let previousIndex = selectedIndex
selectedIndex = sender.tag
tabButtons[previousIndex!].isSelected = false
let previousVC = viewControllers[previousIndex!]
// remove previous VC
previousVC.willMove(toParentViewController: nil)
previousVC.view.removeFromSuperview()
previousVC.removeFromParentViewController()
// set current VC
sender.isSelected = true
let vc = viewControllers[selectedIndex]
addChildViewController(vc)
// Adjust the size to match content view
vc.view.frame = contentView.bounds
contentView.addSubview(vc.view)
vc.didMove(toParentViewController: self)
}
I could set a default tab bar index selectedIndex when the tab bar view is loaded. However, how can I switch to next tab bar in homeViewController (without tapping tab bar buttons)?
This doesn't work in homeViewController
TabBarViewController().tabButtons[2].isSelected = true TabBarViewController().didPressTab(TabBarViewController().tabButtons[2])
I'm not sure how to get the running tab controller, set the selectedIndex, and update subview in the subview controllers.
All you need to do is to call tabBar.setSelectedViewController: and pass the view controller.
If you only know the tab index, you call tabBar.viewControllers[index] and get the view controller.
I finally use Delegate to solve.
In SubViewController add protocol
protocol SubViewControllerDelegate {
func transferToView(index: Int)
}
and declare this in the class
var delegate: SubViewControllerDelegate?
In TabBarViewController set to conform SubViewControllerDelegate
Implement the method
func transferToView(index: Int) {
tabButtons[index].isSelected = true
didPressTab(tabButtons[index])
}
Set delegate
subViewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
let subVC = subViewController as! SubViewController
subVC.delegate = self