Reputation: 319
I have a ViewControllerOne
with a tableView
constrained to a superview
and filled with a content. User can scroll down some content, then switch to ViewControllerTwo
and change tableView
data source content on another.
When that happens and user returns to the ViewControllerOne
I want the VC to be reset on its initial state at the top with a Large Title
and a new content, but with a workaround I found it scrolls only till the tableView
top and stops on a Small Title
.
Here is the code:
When user picks a new Data Source in ViewControllerTwo
I save it as a bool
in UserDefaults
:
UserDefaults.standard.set(true, forKey: "newDataSourcePicked")
In ViewControllerOne I trigger the scrolling method in a viewWillAppear()
:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
scrollVCUp()
}
Here is scrollVCUp()
. Here I use the saved bool. Also use delay because its not scrolling without it:
func scrollVCUp() {
if newDataSourcePicked {
traitCollection.verticalSizeClass == .compact ? setVCOffset(with: view.safeAreaInsets.top, and: updateLabelTopInset, delayValue: 0.1) : setVCOffset(with: biggestTopSafeAreaInset, and: updateLabelTopInset, delayValue: 0.1)
UserDefaults.standard.set(false, forKey: "newDataSourcePicked")
}
}
Here is setVCOffset()
:
func setVCOffset(with viewInset: CGFloat, and labelInset: CGFloat, delayValue: Double = 0.0) {
let firstVC = navigationController?.viewControllers.first as? CurrencyViewController
guard let scrollView = firstVC?.view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView else { return }
if delayValue > 0.0 {
DispatchQueue.main.asyncAfter(deadline: .now() + delayValue) {
scrollView.setContentOffset(CGPoint(x: 0, y: -(viewInset - labelInset)), animated: true)
}
} else {
scrollView.setContentOffset(CGPoint(x: 0, y: -(viewInset - labelInset)), animated: true)
}
}
I also have a tabBar
and when I use the same code to scroll ViewControllerOne
by tapping on a tabBar
it scrolls and shows a Large Title
, but doesn't work if we switch to another VC
and back.
Here is a gif:
What should I do to scroll and always show a Large Title
?
Upvotes: 2
Views: 950
Reputation: 626
I found two possible approaches:
Approach 1
Don't use the same UIViewController
instance, that holds the UITableView
. Create a new one.
(Your case: when ViewControllerOne
push ViewControllerTwo
).
With this approach you get the "fresh" layout with large title every time you push the VC.
Approach 2
Scroll by calculating the UITableView.contentOffset
. Use for that adjustedContentInset.top
and round the value.
With this approach you get the same result like approach 1, but with a visible back scrolling animation.
class ViewControllerTwo {
private var _adjustedContentInsetTopRounded: CGFloat?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let y = _adjustedContentInsetTopRounded {
DispatchQueue.main.async {
self.tableView.setContentOffset(
CGPoint(
x: 0,
y: -y
),
animated: true
)
}
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
_adjustedContentInsetTopRounded = tableView.adjustedContentInset.top.rounded(.up)
}
}
Upvotes: 1