Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/docs-reanimated/docs/device/useAnimatedKeyboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,13 @@ import AnimatedKeyboardSrc from '!!raw-loader!@site/src/examples/AnimatedKeyboar

- On Android, using the `useAnimatedKeyboard` hook expands root view to full screen ([immersive mode](https://developer.android.com/develop/ui/views/layout/immersive)) and takes control over insets management.

- When `isStatusBarTranslucentAndroid` is `false` it applies the top and bottom margins according to the insets.
- When `isStatusBarTranslucentAndroid` is `false` it applies the top margin according to the insets.

- When `isStatusBarTranslucentAndroid` is `true` it applies bottom padding according to the navigation inset and sets top margin to `0`.
- When `isStatusBarTranslucentAndroid` is `true` it sets top margin to `0`.

- When `isNavigationBarTranslucentAndroid` is `false` it applies the bottom margin according to the insets.

- When `isNavigationBarTranslucentAndroid` is `true` it sets bottom margin to `0`.

- On Android, when using navigation with native header, `isStatusBarTranslucentAndroid` doesn't affect the top inset.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Properties:

- `isStatusBarTranslucentAndroid`[bool] - if you want to use translucent status bar on Android, set this option to `true`. Defaults to `false`. Ignored on iOS.

- `isNavigationBarTranslucentAndroid`[bool] - if you want to use translucent navigation bar on Android, set this option to `true`. Defaults to `false`. Ignored on iOS.

### Example

```js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,8 @@ void NativeReanimatedModule::initializeLayoutAnimations() {
jsi::Value NativeReanimatedModule::subscribeForKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &handlerWorklet,
const jsi::Value &isStatusBarTranslucent) {
const jsi::Value &isStatusBarTranslucent,
const jsi::Value &isNavigationBarTranslucent) {
auto shareableHandler = extractShareableOrThrow<ShareableWorklet>(
rt,
handlerWorklet,
Expand All @@ -886,7 +887,8 @@ jsi::Value NativeReanimatedModule::subscribeForKeyboardEvents(
uiWorkletRuntime_->runGuarded(
shareableHandler, jsi::Value(keyboardState), jsi::Value(height));
},
isStatusBarTranslucent.getBool());
isStatusBarTranslucent.getBool(),
isNavigationBarTranslucent.getBool());
}

void NativeReanimatedModule::unsubscribeFromKeyboardEvents(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec {
jsi::Value subscribeForKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &keyboardEventContainer,
const jsi::Value &isStatusBarTranslucent) override;
const jsi::Value &isStatusBarTranslucent,
const jsi::Value &isNavigationBarTranslucent) override;
void unsubscribeFromKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &listenerId) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ static jsi::Value SPEC_PREFIX(subscribeForKeyboardEvents)(
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->subscribeForKeyboardEvents(rt, std::move(args[0]), std::move(args[1]));
->subscribeForKeyboardEvents(
rt, std::move(args[0]), std::move(args[1]), std::move(args[2]));
}

static jsi::Value SPEC_PREFIX(unsubscribeFromKeyboardEvents)(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ class JSI_EXPORT NativeReanimatedModuleSpec : public TurboModule {
virtual jsi::Value subscribeForKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &keyboardEventContainer,
const jsi::Value &isStatusBarTranslucent) = 0;
const jsi::Value &isStatusBarTranslucent,
const jsi::Value &isNavigationBarTranslucent) = 0;
virtual void unsubscribeFromKeyboardEvents(
jsi::Runtime &rt,
const jsi::Value &listenerId) = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ using ConfigurePropsFunction = std::function<void(
const jsi::Value &uiProps,
const jsi::Value &nativeProps)>;
using KeyboardEventSubscribeFunction =
std::function<int(std::function<void(int, int)>, bool)>;
std::function<int(std::function<void(int, int)>, bool, bool)>;
using KeyboardEventUnsubscribeFunction = std::function<void(int)>;
using MaybeFlushUIUpdatesQueueFunction = std::function<void()>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,14 +416,16 @@ void NativeProxy::setGestureState(int handlerTag, int newState) {

int NativeProxy::subscribeForKeyboardEvents(
std::function<void(int, int)> callback,
bool isStatusBarTranslucent) {
bool isStatusBarTranslucent,
bool isNavigationBarTranslucent) {
static const auto method =
getJniMethod<int(KeyboardWorkletWrapper::javaobject, bool)>(
getJniMethod<int(KeyboardWorkletWrapper::javaobject, bool, bool)>(
"subscribeForKeyboardEvents");
return method(
javaPart_.get(),
KeyboardWorkletWrapper::newObjectCxxArgs(std::move(callback)).get(),
isStatusBarTranslucent);
isStatusBarTranslucent,
isNavigationBarTranslucent);
}

void NativeProxy::unsubscribeFromKeyboardEvents(int listenerId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ class NativeProxy : public jni::HybridClass<NativeProxy> {
void unregisterSensor(int sensorId);
int subscribeForKeyboardEvents(
std::function<void(int, int)> callback,
bool isStatusBarTranslucent);
bool isStatusBarTranslucent,
bool isNavigationBarTranslucent);
void unsubscribeFromKeyboardEvents(int listenerId);
#ifdef RCT_NEW_ARCH_ENABLED
// nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ public int getHeight() {
return mHeight;
}

public void updateHeight(WindowInsetsCompat insets) {
public void updateHeight(WindowInsetsCompat insets, boolean isNavigationBarTranslucent) {
int contentBottomInset = insets.getInsets(CONTENT_TYPE_MASK).bottom;
int systemBarBottomInset = insets.getInsets(SYSTEM_BAR_TYPE_MASK).bottom;
int systemBarBottomInset =
isNavigationBarTranslucent ? 0 : insets.getInsets(SYSTEM_BAR_TYPE_MASK).bottom;
int keyboardHeightDip = contentBottomInset - systemBarBottomInset;
int keyboardHeight = (int) PixelUtil.toDIPFromPixel(Math.max(0, keyboardHeightDip));
if (keyboardHeight <= 0 && mState == KeyboardState.OPEN) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ public class KeyboardAnimationCallback extends WindowInsetsAnimationCompat.Callb
private final Keyboard mKeyboard;
private final NotifyAboutKeyboardChangeFunction mNotifyAboutKeyboardChange;
private static final int CONTENT_TYPE_MASK = WindowInsetsCompat.Type.ime();
private final boolean mIsNavigationBarTranslucent;

public KeyboardAnimationCallback(
Keyboard keyboard, NotifyAboutKeyboardChangeFunction notifyAboutKeyboardChange) {
Keyboard keyboard,
NotifyAboutKeyboardChangeFunction notifyAboutKeyboardChange,
boolean isNavigationBarTranslucent) {
super(WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE);
mNotifyAboutKeyboardChange = notifyAboutKeyboardChange;
mIsNavigationBarTranslucent = isNavigationBarTranslucent;
mKeyboard = keyboard;
}

Expand Down Expand Up @@ -43,7 +47,7 @@ public WindowInsetsCompat onProgress(
}
}
if (isAnyKeyboardAnimationRunning) {
mKeyboard.updateHeight(insets);
mKeyboard.updateHeight(insets, mIsNavigationBarTranslucent);
mNotifyAboutKeyboardChange.call();
}
return insets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ public KeyboardAnimationManager(WeakReference<ReactApplicationContext> reactCont
}

public int subscribeForKeyboardUpdates(
KeyboardWorkletWrapper callback, boolean isStatusBarTranslucent) {
KeyboardWorkletWrapper callback,
boolean isStatusBarTranslucent,
boolean isNavigationBarTranslucent) {
int listenerId = mNextListenerId++;
if (mListeners.isEmpty()) {
KeyboardAnimationCallback keyboardAnimationCallback =
new KeyboardAnimationCallback(mKeyboard, this::notifyAboutKeyboardChange);
new KeyboardAnimationCallback(
mKeyboard, this::notifyAboutKeyboardChange, isNavigationBarTranslucent);
mWindowsInsetsManager.startObservingChanges(
keyboardAnimationCallback, isStatusBarTranslucent);
keyboardAnimationCallback, isStatusBarTranslucent, isNavigationBarTranslucent);
}
mListeners.put(listenerId, callback);
return listenerId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
public class WindowsInsetsManager {

private boolean mIsStatusBarTranslucent = false;
private boolean mIsNavigationBarTranslucent = false;
private final WeakReference<ReactApplicationContext> mReactContext;
private final Keyboard mKeyboard;
private final NotifyAboutKeyboardChangeFunction mNotifyAboutKeyboardChange;
Expand All @@ -35,8 +36,11 @@ private Activity getCurrentActivity() {
}

public void startObservingChanges(
KeyboardAnimationCallback keyboardAnimationCallback, boolean isStatusBarTranslucent) {
KeyboardAnimationCallback keyboardAnimationCallback,
boolean isStatusBarTranslucent,
boolean isNavigationBarTranslucent) {
mIsStatusBarTranslucent = isStatusBarTranslucent;
mIsNavigationBarTranslucent = isNavigationBarTranslucent;
updateWindowDecor(false);

Activity currentActivity = getCurrentActivity();
Expand All @@ -51,7 +55,7 @@ public void startObservingChanges(
}

public void stopObservingChanges() {
updateWindowDecor(!mIsStatusBarTranslucent);
updateWindowDecor(!mIsStatusBarTranslucent && !mIsNavigationBarTranslucent);
updateInsets(0, 0);

Activity currentActivity = getCurrentActivity();
Expand Down Expand Up @@ -83,7 +87,7 @@ private void updateWindowDecor(boolean decorFitsSystemWindow) {
private WindowInsetsCompat onApplyWindowInsetsListener(View view, WindowInsetsCompat insets) {
WindowInsetsCompat defaultInsets = ViewCompat.onApplyWindowInsets(view, insets);
if (mKeyboard.getState() == KeyboardState.OPEN) {
mKeyboard.updateHeight(insets);
mKeyboard.updateHeight(insets, mIsNavigationBarTranslucent);
mNotifyAboutKeyboardChange.call();
}
setWindowInsets(defaultInsets);
Expand Down Expand Up @@ -120,11 +124,12 @@ private FrameLayout.LayoutParams getLayoutParams(int paddingTop, int paddingBott
int matchParentFlag = FrameLayout.LayoutParams.MATCH_PARENT;
FrameLayout.LayoutParams params =
new FrameLayout.LayoutParams(matchParentFlag, matchParentFlag);
if (mIsStatusBarTranslucent) {
params.setMargins(0, 0, 0, paddingBottom);
} else {
params.setMargins(0, paddingTop, 0, paddingBottom);
}

params.setMargins(
0,
mIsStatusBarTranslucent ? 0 : paddingTop,
0,
mIsNavigationBarTranslucent ? 0 : paddingBottom);
return params;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,11 @@ public void unregisterSensor(int sensorId) {

@DoNotStrip
public int subscribeForKeyboardEvents(
KeyboardWorkletWrapper keyboardWorkletWrapper, boolean isStatusBarTranslucent) {
KeyboardWorkletWrapper keyboardWorkletWrapper,
boolean isStatusBarTranslucent,
boolean isNavigationBarTranslucent) {
return keyboardAnimationManager.subscribeForKeyboardUpdates(
keyboardWorkletWrapper, isStatusBarTranslucent);
keyboardWorkletWrapper, isStatusBarTranslucent, isNavigationBarTranslucent);
}

@DoNotStrip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,10 @@ UnregisterSensorFunction makeUnregisterSensorFunction(ReanimatedSensorContainer
KeyboardEventSubscribeFunction makeSubscribeForKeyboardEventsFunction(REAKeyboardEventObserver *keyboardObserver)
{
auto subscribeForKeyboardEventsFunction =
[=](std::function<void(int keyboardState, int height)> keyboardEventDataUpdater, bool isStatusBarTranslucent) {
// ignore isStatusBarTranslucent - it's Android only
[=](std::function<void(int keyboardState, int height)> keyboardEventDataUpdater,
bool isStatusBarTranslucent,
bool isNavigationBarTranslucent) {
// ignore isStatusBarTranslucent and isNavigationBarTranslucent - those are Android only
return [keyboardObserver subscribeForKeyboardEvents:^(int keyboardState, int height) {
keyboardEventDataUpdater(keyboardState, height);
}];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export interface NativeReanimatedModule {
configureProps(uiProps: string[], nativeProps: string[]): void;
subscribeForKeyboardEvents(
handler: ShareableRef<number>,
isStatusBarTranslucent: boolean
isStatusBarTranslucent: boolean,
isNavigationBarTranslucent: boolean
): number;
unsubscribeFromKeyboardEvents(listenerId: number): void;
configureLayoutAnimationBatch(
Expand Down Expand Up @@ -212,11 +213,13 @@ See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooti

subscribeForKeyboardEvents(
handler: ShareableRef<number>,
isStatusBarTranslucent: boolean
isStatusBarTranslucent: boolean,
isNavigationBarTranslucent: boolean
) {
return this.InnerNativeModule.subscribeForKeyboardEvents(
handler,
isStatusBarTranslucent
isStatusBarTranslucent,
isNavigationBarTranslucent
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/react-native-reanimated/src/commonTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ export interface MeasuredDimensions {

export interface AnimatedKeyboardOptions {
isStatusBarTranslucentAndroid?: boolean;
isNavigationBarTranslucentAndroid?: boolean;
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/react-native-reanimated/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ export function subscribeForKeyboardEvents(
}
return NativeReanimatedModule.subscribeForKeyboardEvents(
makeShareableCloneRecursive(handleAndFlushAnimationFrame),
options.isStatusBarTranslucentAndroid ?? false
options.isStatusBarTranslucentAndroid ?? false,
options.isNavigationBarTranslucentAndroid ?? false
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import { KeyboardState } from '../commonTypes';
* @see https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedKeyboard
*/
export function useAnimatedKeyboard(
options: AnimatedKeyboardOptions = { isStatusBarTranslucentAndroid: false }
options: AnimatedKeyboardOptions = {
isStatusBarTranslucentAndroid: false,
isNavigationBarTranslucentAndroid: false,
}
): AnimatedKeyboardInfo {
const ref = useRef<AnimatedKeyboardInfo | null>(null);
const listenerId = useRef<number>(-1);
Expand Down