Files
react-navigation/android/src/main/java/com/swmansion/rnscreens/Screen.java
Krzysztof Magiera d4636d3130 Android native stack bugfixes. (#190)
A few bugs fixed with android native stack in this commit:
 - fixed a problem with views not resizing when keyboard appears, the bug was due to onMeasure forwardin getHeight which was the old height of the container instead of the changed one
 - fixed a problem with back button behavior not being consistent. Now back button is controlled by 'gestureEnabled' to emulate iOS behavior where there is no hw back button but you can swipe back instead.
 - added compatibility for "contained" modal styles - for now we always render "containted" fragments on Android, plan to add a way to render in dialogs in the future
2019-10-22 23:22:48 +02:00

173 lines
4.9 KiB
Java

package com.swmansion.rnscreens;
import android.content.Context;
import android.graphics.Paint;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.facebook.react.bridge.GuardedRunnable;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.uimanager.UIManagerModule;
public class Screen extends ViewGroup implements ReactPointerEventsView {
public enum StackPresentation {
PUSH,
MODAL,
TRANSPARENT_MODAL
}
public enum StackAnimation {
DEFAULT,
NONE,
FADE
}
private static OnAttachStateChangeListener sShowSoftKeyboardOnAttach = new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
InputMethodManager inputMethodManager =
(InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(view, 0);
view.removeOnAttachStateChangeListener(sShowSoftKeyboardOnAttach);
}
@Override
public void onViewDetachedFromWindow(View view) {
}
};
private @Nullable Fragment mFragment;
private @Nullable ScreenContainer mContainer;
private boolean mActive;
private boolean mTransitioning;
private StackPresentation mStackPresentation = StackPresentation.PUSH;
private StackAnimation mStackAnimation = StackAnimation.DEFAULT;
public Screen(ReactContext context) {
super(context);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
final int width = r - l;
final int height = b - t;
final ReactContext reactContext = (ReactContext) getContext();
reactContext.runOnNativeModulesQueueThread(
new GuardedRunnable(reactContext) {
@Override
public void runGuarded() {
reactContext.getNativeModule(UIManagerModule.class)
.updateNodeSize(getId(), width, height);
}
});
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
clearDisappearingChildren();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// This method implements a workaround for RN's autoFocus functionality. Because of the way
// autoFocus is implemented it sometimes gets triggered before native text view is mounted. As
// a result Android ignores calls for opening soft keyboard and here we trigger it manually
// again after the screen is attached.
View view = getFocusedChild();
if (view != null) {
while (view instanceof ViewGroup) {
view = ((ViewGroup) view).getFocusedChild();
}
if (view instanceof TextView) {
TextView textView = (TextView) view;
if (textView.getShowSoftInputOnFocus()) {
textView.addOnAttachStateChangeListener(sShowSoftKeyboardOnAttach);
}
}
}
}
/**
* While transitioning this property allows to optimize rendering behavior on Android and provide
* a correct blending options for the animated screen. It is turned on automatically by the container
* when transitioning is detected and turned off immediately after
*/
public void setTransitioning(boolean transitioning) {
if (mTransitioning == transitioning) {
return;
}
mTransitioning = transitioning;
super.setLayerType(transitioning ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
}
public void setStackPresentation(StackPresentation stackPresentation) {
mStackPresentation = stackPresentation;
}
public void setStackAnimation(StackAnimation stackAnimation) {
mStackAnimation = stackAnimation;
}
public StackAnimation getStackAnimation() {
return mStackAnimation;
}
public StackPresentation getStackPresentation() {
return mStackPresentation;
}
@Override
public PointerEvents getPointerEvents() {
return mTransitioning ? PointerEvents.NONE : PointerEvents.AUTO;
}
@Override
public void setLayerType(int layerType, @Nullable Paint paint) {
// ignore - layer type is controlled by `transitioning` prop
}
protected void setContainer(@Nullable ScreenContainer container) {
mContainer = container;
}
protected void setFragment(Fragment fragment) {
mFragment = fragment;
}
protected @Nullable Fragment getFragment() {
return mFragment;
}
protected @Nullable ScreenContainer getContainer() {
return mContainer;
}
public void setActive(boolean active) {
if (active == mActive) {
return;
}
mActive = active;
if (mContainer != null) {
mContainer.notifyChildUpdate();
}
}
public boolean isActive() {
return mActive;
}
}