Commit 028c47c
authored
fix(iOS, Tabs): bottom accessory opacity on appearance change (#3467)
## Description
Fixes bottom accessory content view switching workaround on appearance
change.
| before | after |
| --- | --- |
| <video
src="https://github.com/user-attachments/assets/9a8c15ec-b140-4f90-b0f6-1bb1af2f5657"
/> | <video
src="https://github.com/user-attachments/assets/0630273c-e412-4fcb-ac6a-287a6dba668d"
/> |
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`](https://developer.apple.com/documentation/uikit/uitraitenvironment/traitcollectiondidchange(_:)?language=objc)
is a deprecated API for handling trait changes. For detecting current
bottom accessory environment, we use
[`registerForTraitChanges:withHandler:`](https://developer.apple.com/documentation/uikit/uitraitchangeobservable-7qoet/registerfortraitchanges:withhandler:?language=objc).
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:`](https://developer.apple.com/documentation/uikit/uitraitcollection/hasdifferentcolorappearance(comparedto:)?language=objc)
can be replaced with new API and
[`systemTraitsAffectingColorAppearance`](https://developer.apple.com/documentation/uikit/uitraitcollection/systemtraitsaffectingcolorappearance-18zhm?language=objc)
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:
software-mansion/react-native-screens-labs#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:
```tsx
bottomAccessory={env => {
if (env === 'inline') {
return <Text style={{ marginLeft: 40 }}>Inline</Text>;
}
return (
<Text style={{ textAlign: 'right', marginRight: 40 }}>
Not Inline
</Text>
);
}}
```
## Checklist
- [x] Included code example that can be used to test this change
- [x] Ensured that CI passes1 parent 5463180 commit 028c47c
File tree
1 file changed
+13
-0
lines changed- ios/bottom-tabs/accessory
1 file changed
+13
-0
lines changedLines changed: 13 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
43 | 56 | | |
44 | 57 | | |
45 | 58 | | |
| |||
0 commit comments