Skip to content

Conversation

t0maboro
Copy link
Contributor

@t0maboro t0maboro commented Aug 11, 2025

Description

This PR is changing the approach for calculating edge insets of the navigation bar.
On iOS 26, the hierarchy has changed significantly, resulting in placing too long header content, which might be covered by the right button.

Old hierarchy:

Class: UINavigationBar | Frame: {{0, 56.333333333333343}, {440, 44}} | Margins => top: 13.67, leading: 8.00, bottom: 8.00, trailing: 8.00
  Class: _UINavigationBarContentView | Frame: {{0, 0}, {440, 44}} | Margins => top: 5.67, leading: 20.00, bottom: 0.00, trailing: 20.00
    ...
    Class: _UINavigationBarTitleControl | Frame: {{66, 13.666666666666664}, {268, 17}} | Margins => top: 8.00, leading: 8.00, bottom: 8.00, trailing: 8.00

New hierarchy:

Class: UINavigationBar | Frame: {{0, 56.333333333333343}, {440, 54}} | Margins => top: 5.67, leading: 20.00, bottom: 0.00, trailing: 20.00
  Class: UIKit.NavigationBarContentView | Frame: {{0, 0}, {440, 54}} | Margins => top: 5.67, leading: 0.00, bottom: 0.00, trailing: 0.00
    Class: UIKit.NavigationBarTransitionContainer | Frame: {{0, 0}, {440, 54}} | Margins => top: 8.00, leading: 8.00, bottom: 8.00, trailing: 8.00
      Class: _UINavigationBarHostedViewContainer | Frame: {{0, 0}, {440, 54}} | Margins => top: 8.00, leading: 8.00, bottom: 8.00, trailing: 8.00
        Class: _UINavigationBarHostedViewWrapper | Frame: {{80, 13.5}, {240, 17}} | Margins => top: 8.00, leading: 8.00, bottom: 8.00, trailing: 8.00
          Class: _UINavigationBarTitleControl | Frame: {{0, 0}, {240, 17}} | Margins => top: 8.00, leading: 8.00, bottom: 8.00, trailing: 8.00

In the new approach, I'm summing up all directionalLayoutMargins between _UINavigationBarTitleControl and NavigationBarContentView. I know that this approach doesn't seem to be super-solid, but somehow I need to traverse the structure to get _UINavigationBarTitleControl and calculate cumulative layout properly.

Changes

  • Extended UINavigationBar with the new method for calculating the insets between the content and title views.

Screenshots / GIFs

Here you can add screenshots / GIFs documenting your change.

You can add before / after section if you're changing some behavior.

Before

Screenshot 2025-08-11 at 15 35 18

After

Screenshot 2025-08-11 at 15 33 38

Test code and steps to reproduce

TestHeaderTitle example on iOS 26 and 18.

Checklist

  • Included code example that can be used to test this change
  • Ensured that CI passes

@t0maboro t0maboro self-assigned this Aug 11, 2025
@kkafar
Copy link
Member

kkafar commented Aug 11, 2025

It looks like they're using SwiftUI to implement UIKit xD

@kkafar kkafar changed the title fix(iOS, Stack) Fix calculating insets for header title fix(iOS, Stack): Fix calculating insets for header title Aug 11, 2025
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few comments & questions

return totalMargins;
}

UIView *currentView = titleControl.superview;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the snippet you provided in PR description I can observe, that titleControl has non-zero insets. Why do we skip them by starting from superview?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm following the same approach as for the < iOS26 implementation for which we stopped at _UINavigationBarTitleControl level

Comment on lines 55 to 105
while (currentView && currentView != self) {
NSDirectionalEdgeInsets margins = currentView.directionalLayoutMargins;
totalMargins.top += margins.top;
totalMargins.leading += margins.leading;
totalMargins.bottom += margins.bottom;
totalMargins.trailing += margins.trailing;
currentView = currentView.superview;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop also does not include insets of UINavigationBar itself, is it intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NavigationBar was left in their old calculation method: https://github.com/software-mansion/react-native-screens/blob/main/ios/RNSScreenStackHeaderConfig.mm#L256. For this change, I intentionally wanted to calculate everything in between UINavigationBar and title control view.

@t0maboro t0maboro requested a review from kkafar August 11, 2025 16:35
@t0maboro t0maboro marked this pull request as draft August 12, 2025 07:25
@t0maboro t0maboro force-pushed the @t0maboro/fix-test-header-title-insets branch from 74d7168 to acdc220 Compare August 21, 2025 11:13
@t0maboro
Copy link
Contributor Author

This PR introduces a regression with shrinking title component in landscape mode too much. I'm working on another approach for calculating edge insets. Closing this in favor of: #3210

@t0maboro t0maboro closed this Sep 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants