-
-
Notifications
You must be signed in to change notification settings - Fork 597
fix(iOS, Tabs): tab screen height when tabs are rendered dynamically #3425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(iOS, Tabs): tab screen height when tabs are rendered dynamically #3425
Conversation
|
I've tested tabs with padding/other views around them on iPad as well and everything seems to be working correctly. |
| // On Fabric, when tabs are rendered dynamically, tab screens receive incorrect frame from UIKit layout | ||
| // (frame matches full window size instead of the size of the host). To mitigate this, we override | ||
| // `layoutSubviews` and assign correct frame ourselves. | ||
| // TODO: investigate why we receive incorrect frame, fix and remove this workaround |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you include an issue number for the TODO ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this is not a workaround anymore and layout constraints should stay so no need to mark them for removal. I will keep the ticket for research because it might be useful to know why this happens (but it's not crucial).
kmichalikk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀
padded-bottom-tabs-uh-oh.mov
Thanks for catching this! I confirmed that this issue visible on the recording is reproducible in bare UIKit app on iOS 26.1. It seems to be fixed on iOS 26.2 beta 3 (but we still need to fix the size of the
UIKit reproimport UIKit
class ReproductionViewController: UIViewController {
private let hostView: UIView = {
let view = UIView()
view.backgroundColor = .systemGray6
view.layer.borderColor = UIColor.green.cgColor
view.layer.borderWidth = 3.0
return view
}()
private let myTabBarController = UITabBarController()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
setupHostView()
setupTabs()
embedTabBar()
}
private func setupHostView() {
view.addSubview(hostView)
hostView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 50),
hostView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50),
hostView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50),
hostView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50)
])
}
private func embedTabBar() {
myTabBarController.tabBarMinimizeBehavior = .onScrollDown
addChild(myTabBarController)
hostView.addSubview(myTabBarController.view)
myTabBarController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
myTabBarController.view.topAnchor.constraint(equalTo: hostView.topAnchor),
myTabBarController.view.bottomAnchor.constraint(equalTo: hostView.bottomAnchor),
myTabBarController.view.leadingAnchor.constraint(equalTo: hostView.leadingAnchor),
myTabBarController.view.trailingAnchor.constraint(equalTo: hostView.trailingAnchor)
])
myTabBarController.didMove(toParent: self)
}
private func setupTabs() {
let tab1 = ScrollableTabViewController(title: "Home", color: .systemBlue)
let tab2 = ScrollableTabViewController(title: "Settings", color: .systemRed)
myTabBarController.setViewControllers([tab1, tab2], animated: false)
}
}
class ScrollableTabViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIView()
let color: UIColor
init(title: String, color: UIColor) {
self.color = color
super.init(nibName: nil, bundle: nil)
self.title = title
self.tabBarItem = UITabBarItem(title: title, image: UIImage(systemName: "circle"), tag: 0)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupScrollView()
}
func setupScrollView() {
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.backgroundColor = color.withAlphaComponent(0.3)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
contentView.heightAnchor.constraint(equalToConstant: 1500)
])
addLabel(text: "TOP", y: 10)
addLabel(text: "BOTTOM", y: 1450)
}
func addLabel(text: String, y: CGFloat) {
let label = UILabel()
label.text = text
label.font = .boldSystemFont(ofSize: 20)
label.frame = CGRect(x: 20, y: y, width: 200, height: 30)
contentView.addSubview(label)
}
}As for the implementation, I decided to use layout constraints instead of overriding |
kkafar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Description
Fixes incorrect tab screen frame, assigned by UIKit when tabs are rendered dynamically & available space is less that window size.
We enable auto-layout and add constraints so that
tabBarController.view's dimensions matchRNSBottomTabsHostComponentView.Closes https://github.com/software-mansion/react-native-screens-labs/issues/588.
before3425_vid.mov
after3425_vid.mov
We might want to investigate in more detail why we receive the incorrect frame. I created an issue for this: https://github.com/software-mansion/react-native-screens-labs/issues/596.
Changes
tabBarController.view.Test code and steps to reproduce
Run
Test3425.Checklist