I have a custom pop transition and it depends on the UITableView being scrolled to the top before performing the transition. The second I tap the back button of my UIViewController I want to scroll the UITableView up which will then have the correct state for my transition.
I already tried to scroll the UITableView up before the view will get dismissed:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
}
This however failed to scroll at all. How can I move the UITableView to the top before the UIViewController gets dismissed?
Overriding willMove(toParent:) and checking for parent == nil should allow you to perform the animation at the required time. See this response on intercepting nav back button.
Related
When a UIViewController with a UIScrollView is visible on screen, I want to show the UIScrollView scrollbar indicator.
Is there a way to show the indicator?
You can show the scrollbar momentarily with .flashScrollIndicators when the view controller has been added to the view hierarchy and is potentially visible to the user.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
scrollView.flashScrollIndicators()
}
I have a collectionView embedded in a subview of the ViewController. The collectionView has 12 cells. Each cell takes up the whole width and height of the collection view, so that I can achieve the pagination affect. However, when the app starts, I want to show the middle cell like the 6th or 7th one of my collectionView.
P.S. I have the collectionView in a wrapper view, not in my viewController.
In my WrapperView, I added the following method but as this method is called after the collectionView is added, it shows a sudden jump.
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
let indexPath = IndexPath(row: 6, section: 0)
DispatchQueue.main.async {
self.calendarCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
}
}
If I could do it before the collection view appear on the screen, I may be able to fix that problem, but I can't find which method is called before the didAddSubview(_:) method in UIView Life Cycle.
Can anyone give me hint on how to solve this.
After your data source has loaded use:
func selectItem(at indexPath: IndexPath?,
animated: Bool,
scrollPosition: UICollectionView.ScrollPosition)
https://developer.apple.com/documentation/uikit/uicollectionview/1618057-selectitem
Probably best used before the view appears so trigger in viewWillAppear or viewDidLoad
I have a special question and I doesn't find an answer for my case. I have an embedded ViewController in a navigation controller with a Container View. In this Container View is a scrollView. What I want to do is: When I scroll in my ContainerView down I want that the Bar Button Item in the NavigationContoller from my ViewController disappear. When I scroll up it should appear again.
I can hide the whole NavigationBar with the following code, which is in the ContainerViewController.swift-file:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
print("123")
if(velocity.y>0) {
UIView.animate(withDuration: 0.5, delay: 0, options: UIView.AnimationOptions(), animations: {
self.navigationController?.setNavigationBarHidden(true, animated: true)
print("Hide")
}, completion: nil)
} else {
UIView.animate(withDuration: 0.5, delay: 0, options: UIView.AnimationOptions(), animations: {
self.navigationController?.setNavigationBarHidden(false, animated: true)
print("Unhide")
}, completion: nil)
}
}
Is there a similar code that only makes the bar button item disappear? I don't know how to access the bar button item because I can't connect it as an Outlet to the ContainerViewController.swift-file but only to the ViewController.swift-file.
I hope you understand my question and can answer it.
Only the ViewController can change what's in the navigation bar, by changing the contents of its own navigationItem. So you would have to send a message from the ContainerViewController to the ViewController (its parent) and the ViewController would do whatever is desired to its navigationItem.
You can access the bar button items of your navigation controller trough the navigationItem property of navigationController.
For instance, if you want to hide the left bar button item just set navigationController?.navigationItem.leftBarButtonItem.isHidden = true.
In my use case, I want to hide the bottom tabbar when navigating away from UITabbarController.
I was using
let vc = storyboard?.instantiateViewController(withIdentifier: tableData[indexPath.row]["vcIdentifier"]!)
self.hidesBottomBarWhenPushed = true
self.show(vc!, sender: self)
It sorta works, because the pushed view controller doesn't have tabbar at bottom. However, as soon as I click on navigate, the bottom tabbar of the "sender" view controller vanishes and leaves black area.
Please let me know if you need to have more information about anything. Thanks a lot in advance!
If the pushed view controller doesn't have a tab bar at the bottom, you can add this lifecycle of view controller codes.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.tabBar.isHidden = true
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
tabBarController?.tabBar.isHidden = false
}
you can use segue if you want to hide tabbar while going to the next screen. it will automatically hide it.
I have a tab bar with five items, and I am trying to add a functionality to scroll to the top when the user taps the tab bar item again. Added the UITabBarControllerDelegate to the views where I want to trigger the event and also created a function to determine the selected tab bar index.
When I open the app, index 0 is auto-selected and works perfectly. The view auto scrolls to the top when I scroll down and tap the tab bar index. The problem occurs when I go to index 1 and trigger the scroll there. It somehow completely removes the auto-scroll from my first tab bar item.
Selecting other tab bar items without the auto scroll does not affect index 0 at all.
Home (index 0)
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 0 {
self.collectionView?.setContentOffset(CGPoint(x: 0, y: -10), animated: true)
}
}
Users (index 1)
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 1 {
self.tableView?.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
}
}
Anything with a delegate property can only have one delegate assigned to it at any given time. What ever set the delegate most recently will receive the next delegate method call.
In your case you can probably reset the tab controller's delegate to self in each view controller's viewDidAppear method since you want the currently visible view controller to be the current tab controller delegate.
Add the following to each view controller that needs to be the tab controller's delegate:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tabBarController?.delegate = self
}