On Android, the height of the navigation bar does not change after switching the navigation type.
1280103995 opened this issue · comments
Bug summary
In the phone settings, after switching the button navigation to the sliding gesture navigation, the height obtained through NavigationBar.currentHeight
is still the previous value.
Reading NavigationBar.tsx
can see static currentHeight = NativeModule?.navigationBarHeight;
, here a fixed value is returned.
In the StatusBar.js
source code:
static currentHeight: ?number =
Platform.OS ==='android'
? NativeStatusBarManagerAndroid.getConstants().HEIGHT
: null;
In the NativeStatusBarManagerAndroid.js
source code:
getConstants(): {|
+HEIGHT: number,
+DEFAULT_BACKGROUND_COLOR?: number,
|} {
if (constants == null) {
constants = NativeModule.getConstants();
}
return constants;
},
I am not familiar with flow
and typescript
, and I cannot push a PR:disappointed:. Can we learn from this approach?
Device: Samsung Galaxy A51 (Android 11)
Library version
1.0.4
Environment info
System:
OS: macOS 11.5.2
CPU: (6) x64 Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz
Memory: 110.27 MB / 8.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 15.4.0 - /usr/local/bin/node
Yarn: 1.22.17 - /usr/local/bin/yarn
npm: 7.0.15 - /usr/local/bin/npm
Watchman: Not Found
Managers:
CocoaPods: 1.11.2 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
Android SDK: Not Found
IDEs:
Android Studio: 4.2 AI-202.7660.26.42.7486908
Xcode: 12.5/12E262 - /usr/bin/xcodebuild
Languages:
Java: 11.0.8 - /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/javac
Python: 2.7.16 - /usr/bin/python
npmPackages:
@react-native-community/cli: Not Found
react: Not Found
react-native: Not Found
npmGlobalPackages:
*react-native*: Not Found
Steps to reproduce
- In the phone settings, change the button navigation to gesture navigation.
- In
App.tsx
, callNavigationBar.currentHeight
.
Reproducible sample code
I just run the example project in the repository.
That's a little be harder than this, since constants are initialized at app startup (the native status bar module suffer from the same issue).
What can be done for now:
- Replacing constants with methods that return Promises (not a huge fan of that).
- Find a way to detect this change and override constants on the JS side. That's what I do with https://github.com/zoontek/react-native-localize
That's a little be harder than this, since constants are initialized at app startup (the native status bar module suffer from the same issue).
What can be done for now:
- Replacing constants with methods that return Promises (not a huge fan of that).
- Find a way to detect this change and override constants on the JS side. That's what I do with https://github.com/zoontek/react-native-localize
You are right, referring to react native's approach is I was wrong.
I can receive the latest value by doing this, but the component needs to be rendered.
RNBarsModule.java
public void init() {
...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ViewCompat.setOnApplyWindowInsetsListener(activity.getWindow().getDecorView(), (v, insets) -> {
int naviHeight;
if (insets != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
naviHeight = insets.getInsets(WindowInsets.Type.navigationBars()).bottom;
} else {
naviHeight = insets.getSystemWindowInsetBottom();
}
sendEvent(PixelUtil.toDIPFromPixel(naviHeight));
}
if (insets != null) {
return ViewCompat.onApplyWindowInsets(v, insets);
}
return null;
});
}
}
private static void sendEvent(float naviHeight) {
if (mReactContext == null) return;
WritableMap event = Arguments.createMap();
event.putDouble("navigationBarHeight", naviHeight);
mReactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("rnBarsNavHeight", event);
}
NavigationBar.tsx
import * as React from "react";
import { DeviceEventEmitter, Platform } from "react-native";
import { NativeModule } from "./module";
import { NavigationBarProps } from "./types";
const isSupportedPlatform = Platform.OS === "android" && Platform.Version >= 27;
// Listen here
DeviceEventEmitter.addListener('rnBarsNavHeight', data => {
StatusBar.currentHeight = data.navigationBarHeight;
console.log('NavigationBar Change: ', StatusBar.currentHeight)
})
export class NavigationBar extends React.Component<StatusBarProps> {
private static propsStack: NavigationBarProps[] = [];
private static immediate: NodeJS.Immediate | null = null;
private static mergedProps: NavigationBarProps | null = null;
........
}
I will probably just remove the constants, it's better to use https://github.com/th3rdwave/react-native-safe-area-context which achieve exactly the same job (and more!)
I removed these constants in favor of react-native-safe-area-context: https://github.com/zoontek/react-native-bars/releases/tag/1.1.0