Skip to content

Commit cc73b18

Browse files
kkafarmaciekstosio
andauthored
fix(iOS): prevent back button icon from "jumping" during pop animation when display mode minimal is set (#2800)
## Description See: react-navigation/react-navigation#12500 for issue description with videos. We can use the backbuttondisplaymode to hide the backbuttontitle avoiding setting the title to `nil` and therefore preventing the UIKit buggy back button icon animation. @maciekstosio: We agreed to leave `backTitleVisible`, so the API doesn't change in a minor version. The expected behavior is that `backTitleVisible: false` will work as "kill switch" and ignore other back button properties. When `backTitleVisible: true` other properties will work (including backButtonDisplayMode), but note that iOS omits `backButtonDisplayMode` when custom back button is provided (so when any of `backTitleFontSize`, `backTitleFontFamily`, `headerBackButtonMenuEnabled`, `headerBackTitle` is used). ## Changes :point_up: ## Test code and steps to reproduce You can use `Test1084`. 1. Simply set the `headerBackButtonDisplayMode: 'minimal'` on the second push screen. 2. Set `headerLargeTitle: true` on the first push screen. ## How this has been tested @maciekstosio: I tested RNScreens properties by modifying props in `react-navigation/packages/native-stack/src/views/useHeaderConfigProps.tsx`. I used Test1084, with the first screen having `headerLargeTitle: true`. **Tests:** When `backTitleVisible: false`: - backButtonDisplayMode is ignored - backTitleFontSize is ignored - backTitle is ignored (but it changes title in backButtonMenu) - disableBackButtonMenu is ignored When `backTitleVisible: true | undefined`: - `backButtonDisplayMode: minimal` works - `backButtonDisplayMode: generic` works - `backButtonDisplayMode: default` works - `backTitle` works and overrides `backButtonDisplayMode` - `headerBackTitleStyle.fontSize` works and overrides `backButtonDisplayMode` - `headerBackButtonMenuEnabled` works and overrides `backButtonDisplayMode` ## Checklist - [ ] Ensured that CI passes --------- Co-authored-by: Maciej Stosio <[email protected]>
1 parent f15f1b7 commit cc73b18

5 files changed

Lines changed: 38 additions & 23 deletions

File tree

guides/GUIDE_FOR_LIBRARY_AUTHORS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,8 @@ Allows for customizing font size to be used for back button title on iOS.
502502

503503
Whether the back button title should be visible. Defaults to `true`.
504504

505+
When set to `false` it works as a "kill switch": it enforces `backButtonDisplayMode=minimal` and ignores `backButtonDisplayMode`, `backTitleFontSize`, `backTitleFontFamily`, `disableBackButtonMenu`, and `backTitle` works only for back button menu.
506+
505507
### `blurEffect` (iOS only)
506508

507509
Blur effect to be applied to the header. Works with `backgroundColor`'s alpha < 1.
@@ -520,7 +522,9 @@ Boolean indicating whether to show the menu on longPress of iOS >= 14 back butto
520522

521523
### `backButtonDisplayMode` (iOS only)
522524

523-
Enum value indicating display mode of **default** back button. It works on iOS >= 14, and is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu` or `backTitle` is set. Otherwise, when the button is customized, under the hood we use iOS native `backButtonItem` which overrides `backButtonDisplayMode`. Read more [#2123](https://github.com/software-mansion/react-native-screens/pull/2123). Possible options:
525+
Enum value indicating display mode of back button. It is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu`, `backTitle` and `backTitleVisible=false` is set. The `backTitleVisible` forces `backButtonDisplayMode: minimal` and omits other values. Read more [#2800](https://github.com/software-mansion/react-native-screens/pull/2800). The other props, under the hood, customize `backButtonItem` which overrides `backButtonDisplayMode`. Read more [#2123](https://github.com/software-mansion/react-native-screens/pull/2123).
526+
527+
Possible options:
524528

525529
- `default` – show given back button previous controller title, system generic or just icon based on available space
526530
- `generic` – show given system generic or just icon based on available space

ios/RNSScreenStackHeaderConfig.mm

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -631,12 +631,9 @@ + (void)updateViewController:(UIViewController *)vc
631631

632632
auto shouldUseCustomBackBarButtonItem = !isBackTitleBlank || config.disableBackButtonMenu;
633633

634-
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_14_0) && \
635-
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
636-
if (@available(iOS 14.0, *)) {
637-
prevItem.backButtonDisplayMode = config.backButtonDisplayMode;
638-
}
639-
#endif
634+
// This has any effect only in case the `backBarButtonItem` is not set.
635+
// We apply it before we configure the back item, because it might get overriden.
636+
prevItem.backButtonDisplayMode = config.backButtonDisplayMode;
640637

641638
if (config.isBackTitleVisible) {
642639
if ((config.backTitleFontFamily &&
@@ -666,11 +663,9 @@ + (void)updateViewController:(UIViewController *)vc
666663
// back button title should be not visible next to back button,
667664
// but it should still appear in back menu (if one is enabled)
668665

669-
// When backBarButtonItem's title is null, back menu will use value
670-
// of backButtonTitle
671-
[backBarButtonItem setTitle:nil];
672-
shouldUseCustomBackBarButtonItem = YES;
673666
prevItem.backButtonTitle = resolvedBackTitle;
667+
prevItem.backButtonDisplayMode = UINavigationItemBackButtonDisplayModeMinimal;
668+
shouldUseCustomBackBarButtonItem = NO;
674669
}
675670

676671
// Prevent unnecessary assignment of backBarButtonItem if it is not customized,

native-stack/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ Boolean indicating whether to show the menu on longPress of iOS >= 14 back butto
8282

8383
#### `backButtonDisplayMode` (iOS only)
8484

85-
Enum value indicating display mode of **default** back button. It works on iOS >= 14, and is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu` or `backTitle` is set. Otherwise, when the button is customized, under the hood we use iOS native `backButtonItem` which overrides `backButtonDisplayMode`. Read more [#2123](https://github.com/software-mansion/react-native-screens/pull/2123). Possible options:
85+
Enum value indicating display mode of back button. It is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu`, `backTitle` and `backTitleVisible=false` is set. The `backTitleVisible` forces `backButtonDisplayMode: minimal` and omits other values. Read more [#2800](https://github.com/software-mansion/react-native-screens/pull/2800). The other props, under the hood, customize `backButtonItem` which overrides `backButtonDisplayMode`. Read more [#2123](https://github.com/software-mansion/react-native-screens/pull/2123).
86+
87+
Possible options:
8688

8789
- `default` – show given back button previous controller title, system generic or just icon based on available space
8890
- `generic` – show given system generic or just icon based on available space
@@ -128,7 +130,9 @@ Style object for header back title. Supported properties:
128130

129131
#### `headerBackTitleVisible` (iOS only)
130132

131-
Whether the back button title should be visible or not. Defaults to `true`.
133+
Whether the back button title should be visible. Defaults to `true`.
134+
135+
When set to `false` it works as a "kill switch": it enforces `backButtonDisplayMode=minimal` and ignores `backButtonDisplayMode`, `backTitleFontSize`, `backTitleFontFamily`, `disableBackButtonMenu`, and `backTitle` works only for back button menu.
132136

133137
#### `headerCenter`
134138

src/native-stack/types.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,13 @@ export type NativeStackNavigationOptions = {
140140
*/
141141
disableBackButtonMenu?: boolean;
142142
/**
143-
* How the back button behaves by default (when not customized). Available on iOS>=14, and is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu` or `backTitle` is set.
144-
* The following values are currently supported (they correspond to https://developer.apple.com/documentation/uikit/uinavigationitembackbuttondisplaymode?language=objc):
145-
* - "default" – show given back button previous controller title, system generic or just icon based on available space
146-
* - "generic" – show given system generic or just icon based on available space
147-
* - "minimal" – show just an icon
143+
* How the back button behaves. It is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu`, `backTitle` and `backTitleVisible=false` is set.
144+
* The following values are currently supported (they correspond to [UINavigationItemBackButtonDisplayMode](https://developer.apple.com/documentation/uikit/uinavigationitembackbuttondisplaymode?language=objc)):
145+
*
146+
* - `default` – show given back button previous controller title, system generic or just icon based on available space
147+
* - `generic` – show given system generic or just icon based on available space
148+
* - `minimal` – show just an icon
149+
*
148150
* @platform ios
149151
*/
150152
backButtonDisplayMode?: ScreenStackHeaderConfigProps['backButtonDisplayMode'];
@@ -206,6 +208,10 @@ export type NativeStackNavigationOptions = {
206208
};
207209
/**
208210
* Whether the back button title should be visible or not. Defaults to `true`.
211+
*
212+
* When set to `false` it works as a "kill switch": it enforces `backButtonDisplayMode=minimal`, and ignores `backButtonDisplayMode`,
213+
* `headerBackTitleStyle`, `disableBackButtonMenu`. For `headerBackTitle` it works only in back button menu.
214+
*
209215
* Only supported on iOS.
210216
*
211217
* @platform ios

src/types.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,10 @@ export interface ScreenStackHeaderConfigProps extends ViewProps {
544544
backTitleFontSize?: number;
545545
/**
546546
* Whether the back button title should be visible or not. Defaults to `true`.
547+
*
548+
* When set to `false` it works as a "kill switch": it enforces `backButtonDisplayMode=minimal` and ignores `backButtonDisplayMode`, `backTitleFontSize`, `backTitleFontFamily`, `disableBackButtonMenu`.
549+
* For `backTitle` it works only in back button menu.
550+
*
547551
* @platform ios
548552
*/
549553
backTitleVisible?: boolean;
@@ -570,11 +574,13 @@ export interface ScreenStackHeaderConfigProps extends ViewProps {
570574
*/
571575
disableBackButtonMenu?: boolean;
572576
/**
573-
* How the back button behaves by default (when not customized). Available on iOS>=14, and is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu` or `backTitle` is set.
574-
* The following values are currently supported (they correspond to https://developer.apple.com/documentation/uikit/uinavigationitembackbuttondisplaymode?language=objc):
575-
* - "default" – show given back button previous controller title, system generic or just icon based on available space
576-
* - "generic" – show given system generic or just icon based on available space
577-
* - "minimal" – show just an icon
577+
* How the back button behaves. It is used only when none of: `backTitleFontFamily`, `backTitleFontSize`, `disableBackButtonMenu`, `backTitle` and `backTitleVisible=false` is set.
578+
* The following values are currently supported (they correspond to [UINavigationItemBackButtonDisplayMode](https://developer.apple.com/documentation/uikit/uinavigationitembackbuttondisplaymode?language=objc)):
579+
*
580+
* - `default` – show given back button previous controller title, system generic or just icon based on available space
581+
* - `generic` – show given system generic or just icon based on available space
582+
* - `minimal` – show just an icon
583+
*
578584
* @platform ios
579585
*/
580586
backButtonDisplayMode?: BackButtonDisplayMode;

0 commit comments

Comments
 (0)