Skip to content

fix(iOS, Tabs): bottom accessory opacity on appearance change#3467

Merged
kligarski merged 1 commit intomainfrom
@kligarski/fix-bottom-accessory-switching-on-appearance-change
Dec 10, 2025
Merged

fix(iOS, Tabs): bottom accessory opacity on appearance change#3467
kligarski merged 1 commit intomainfrom
@kligarski/fix-bottom-accessory-switching-on-appearance-change

Conversation

@kligarski
Copy link
Copy Markdown
Contributor

@kligarski kligarski commented Dec 10, 2025

Description

Fixes bottom accessory content view switching workaround on appearance change.

before after
before.mov
after.mov

Thanks to @Ubax for reporting the bug.

Reasoning

For RN >= 0.82, bottom accessory uses "content view switching"/"double-rendering" workaround (more details in PR description of #3288). Two bottom accessories are rendered by JS - one for regular environment, one for inline environment and both are inserted to bottom accessory view on the native side. To control which version is visible, we change view.layer.opacity depending on current environment. Opacity is also controlled by RCTViewComponentView in invalidateLayer method. It is called in 2 places:

  • finalizeUpdates,
  • traitCollectionDidChange:.

invalidateLayer overrides our custom opacity, that's why we update it by calling handleContentViewVisibilityForEnvironmentIfNeeded in RNSBottomAccessoryContentComponentView's finalizeUpdates after super implementation is called.

The same was missing for traitCollectionDidChange. The layer invalidation is called when [self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection] (=> when appearance changes).

traitCollectionDidChange is a deprecated API for handling trait changes. For detecting current bottom accessory environment, we use registerForTraitChanges:withHandler:. Unfortunately, we can't use new API for updating opacity as traitCollectionDidChange is called after handlers registered via registerForTraitChanges:withHandler:.

In the future, if RCTViewComponentView switches to new API, we will need to adapt as well. Here is some research that might become useful: hasDifferentColorAppearanceComparedToTraitCollection: can be replaced with new API and systemTraitsAffectingColorAppearance but this API is available on iOS 17+, so we'll need to fallback to hardcoded traits array. Information about which traits affect color appearance can be found in in-code docs for hasDifferentColorAppearanceComparedToTraitCollection:

Currently, a change in any of these traits could affect dynamic colors:
userInterfaceIdiom, userInterfaceStyle, displayGamut, accessibilityContrast, userInterfaceLevel
and more could be added in the future.

We can also research whether it would be possible to update opacity style/prop directly in ShadowNode instead of only native side. There is an existing ticket to research this: https://github.com/software-mansion/react-native-screens-labs/issues/558.

Changes

  • update opacity after RCTViewComponentView invalidates layer on appearance change

Test code and steps to reproduce

Run Test3288. You can modify bottom accessory by changing prop passed to BottomTabsContainer to:

bottomAccessory={env => {
  if (env === 'inline') {
    return <Text style={{ marginLeft: 40 }}>Inline</Text>;
  }
  return (
    <Text style={{ textAlign: 'right', marginRight: 40 }}>
      Not Inline
    </Text>
  );
}}

Checklist

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

@kligarski kligarski marked this pull request as ready for review December 10, 2025 08:20
@kligarski
Copy link
Copy Markdown
Contributor Author

CI fails for reasons unrelated to this PR and should be fixed by #3465.

@kligarski kligarski self-assigned this Dec 10, 2025
@kligarski kligarski added type:bug Something isn't working platform:ios Issue related to iOS part of the library Architecture: New area:tabs Issue related to bottom tabs labels Dec 10, 2025
@kligarski kligarski merged commit 028c47c into main Dec 10, 2025
5 of 6 checks passed
@kligarski kligarski deleted the @kligarski/fix-bottom-accessory-switching-on-appearance-change branch December 10, 2025 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:tabs Issue related to bottom tabs platform:ios Issue related to iOS part of the library type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants