Compare commits

..

18 Commits

Author SHA1 Message Date
osdnk
72037e20fb Bump version -> 2.0.0-alpha.30 2020-01-27 15:32:48 +01:00
Michał Osadnik
69a23f1c9f Remove blocking touch interactions if more than one active scree… (#296)
We believe that it might be better to manage the logic of blocking interactions from JS with setNativeProps and pointerEvents.

The current logic leads to some issues we're facing within React Navigation. There might be a state when more that one screen can be active. E.g. in modals we want to have two screens visible on the stack and have enabled interaction on the bottom one.

New code should not give any issues, because even though we need to handle activation of each screen from JS and this will just introduce an additional native call for enabling / disabling pointer events.

On iOS, we're not using React Native Screens in React Navigation for now and we'd like to focus on it later because right now we're not observing that crucial performance issues.
2020-01-27 11:07:07 +01:00
Janic Duplessis
d32463ee83 Move gestureEnabled config to screen instead of heade… (#254)
When you have 2 screens in a stack with the bottom one with gestureEnabled=false using the back gesture causes the screen to become unresponsive. This seems to be caused by setting interactivePopGestureRecognizer.enabled = NO as soon as the gesture starts. This causes the gesture to cancel immediately and leaves the screen in an unresponsive state.

<Stack><Screen gestureEnabled={false} /><Screen /></Stack>
To fix this instead of using interactivePopGestureRecognizer.enabled we can leverage the existing delegate that we have in RNScreenStack. In gestureRecognizerShouldBegin we can check if the top screen has gestures enabled.

To make this simpler I moved the gestureEnabled config to Screen instead of HeaderConfig. I think it also makes more sense conceptually since the gesture is tied to the screen and not the header. It also simplifies the android code a bit.

This is a breaking change.

Update

This now only moves the config to screen since a separate fix was merged for the bug.
2020-01-24 01:19:38 +01:00
Satyajit Sahoo
2da04f37e6 Fix typo in onDismissed prop name (#288)
The prop is called `onDismissed` according to the code

e00a08a3dc/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.java (L65)
e00a08a3dc/ios/RNSScreen.h (L43)
2020-01-24 01:18:26 +01:00
Krzysztof Magiera
623f9452cb Bump version -> 2.0.0-alpha.29 2020-01-22 21:56:21 +01:00
Krzysztof Magiera
c646a4e7ba Fix rendering title view in native header on Android. (#294)
This change removes the behavior that's been added for an unclear reason. We may consider reverting this one, however I was unable to reproduce a problem when setting header title view layout measurements was necessary. To the contrary it was causing issues in the case when the title header view updates. In such a case we would never update width/height so the updated view might be cropped. In addition we are changing the way we schedule native layout updates. Previously we'd use handler.post but it was causing one frame delay so this change migrates us to use choreographer.
2020-01-22 21:52:56 +01:00
Krzysztof Magiera
a1311cd31d Bump version -> 2.0.0-alpha.28 2020-01-22 15:20:22 +01:00
Krzysztof Magiera
f044334464 Fix focus events in native stack on Android. (#292)
This change fixes the issue with auto focusing text input fields inside native stack. Due to the fact we perform hide and show transactions in order to control back stack the hiding part would propagate visibility change event down the view hierarchy. As a result views would receive that visibility event and blur themselves resulting in textinput not getting the focus when the fragment mounts. It turns out however that for the back stack to function properly we don't need to run hide and show operation within the transaction because show is idempotent. So we change our back stack handling transaction to only call show.
2020-01-22 15:19:54 +01:00
Krzysztof Magiera
1c7ebeba39 Fix NPE on nested stack detach on Android. (#291)
This change fixes crash caused when nested stack is detached due to the parent stack being closed. As a result we may end up in a situation when fragment manager is not yet set despite onDetach callback being call. When fragment manager is not set we can also ignore the operations we should've performed in on detach. This change adds a null check before we call into fragment manager in on detach callback.
2020-01-22 15:16:25 +01:00
Krzysztof Magiera
1493d6f1b8 Bump version -> 2.0.0-alpha.27 2020-01-21 11:51:50 +01:00
Krzysztof Magiera
8cf82d1cbe Fix layout of header items on Android native stack. (#289)
This change fixes the issue when left item added to native stack header on Android would by default be shifted from the screen edge by some amount. This turned out to be the default config of the native toolbar which applies some padding on the left side. WIn this change we reset that padding to always be 0 to let the position be specified from react. Note that the setting we reset does not influence the position of the native back navigation button as Android does not apply the padding in case navigation back icon is rendered.
2020-01-20 22:21:07 +01:00
Krzysztof Magiera
e8403582ae Bump version -> 2.0.0-alpha.26 2020-01-20 10:59:13 +01:00
Tuan Luong
5832593980 [Android] update view when go back to previous screen (#286) 2020-01-20 10:58:19 +01:00
dependabot[bot]
78c7745049 Bump handlebars from 4.1.2 to 4.5.3 (#255)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-17 22:15:51 +01:00
dependabot[bot]
350a80c29b Bump handlebars from 4.2.0 to 4.5.3 in /Example (#256)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.2.0 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.2.0...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-17 22:15:39 +01:00
Michael Wood
c460341a68 Minor typo/wording tweaks (#264) 2020-01-17 22:15:14 +01:00
Angelika Serwa
3fc74e29ab [android] Fix re-attaching ScreenContainer to window (#272)
Code to reproduce and test: https://snack.expo.io/@angelikaserwa/humiliated-bagel.
Switch to the Settings tab, then go back to the Home tab and press the details button. Nothing happens. It was because after re-attaching we were using a destroyed FragmentManager that was cached inside the ScreenContainer class. 
Then, when we go back from Details to Home screen, using a hardware back button, an exception occured: `The specified child already has a parent. You must call removeView() on the child's parent first`.
I fixed this by calling `removeAllViews()` when detaching container from window and forcing an update on re-attach.
2020-01-17 22:13:57 +01:00
Krzysztof Magiera
518c094657 Revert "[Android] Bottom tab not update" (#285)
This reverts commit ca6319d26e.
2020-01-17 22:11:37 +01:00
19 changed files with 106 additions and 134 deletions

View File

@@ -1633,7 +1633,7 @@ combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@^2.19.0, commander@~2.20.0:
commander@^2.19.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@@ -1642,6 +1642,11 @@ commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -2487,9 +2492,9 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
handlebars@^4.0.3:
version "4.2.0"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.2.0.tgz#57ce8d2175b9bbb3d8b3cf3e4217b1aec8ddcb2e"
integrity sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==
version "4.5.3"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
@@ -4806,7 +4811,7 @@ react-native-safe-area-view@^0.14.1:
debounce "^1.2.0"
"react-native-screens@file:..":
version "2.0.0-alpha.3"
version "2.0.0-alpha.22"
dependencies:
debounce "^1.2.0"
@@ -5761,11 +5766,11 @@ uglify-es@^3.1.9:
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
version "3.7.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a"
integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==
dependencies:
commander "~2.20.0"
commander "~2.20.3"
source-map "~0.6.1"
ultron@1.0.x:

View File

@@ -100,12 +100,12 @@ To do that react-native-screens provides you with two components documented belo
### `<ScreenContainer/>`
This component is a container for one or more `Screen` components.
It does not accept other component types are direct children.
The role of container is to control which of its children screens should be attached to the view hierarchy.
It does that by monitoring `active` property of each of its children.
It it possible to have as many `active` children as you'd like but in order for the component to be the most efficient we should keep the number of active screens to the minimum.
In a case of stack navigator or tabs navigator we only want to have one active screen (the top most view on a stack or the selected tab).
Then for the time of transitioning between views we may want to activate a second screen for the duration of transition, and then go back to just one active screen.
It does not accept other component types as direct children.
The role of the container is to control which of its children screens should be attached to the view hierarchy.
It does that by monitoring the `active` property of each of its children.
It is possible to have as many `active` children as you'd like but in order for the component to be the most efficient we should keep the number of active screens to a minimum.
In a case of a stack navigator or tabs navigator we only want to have one active screen (the top most view on a stack or the selected tab).
While transitioning between views we may want to activate a second screen for the duration of the transition, and then go back to just one active screen.
### `<Screen/>`
@@ -131,7 +131,7 @@ Screen stack component expects one or more `Screen` components as direct childre
`StackScreen` extends the capabilities of `Screen` component to allow additional customizations and to make it possible to handle events such as using hardware back or back gesture to dismiss the top screen. Below is the list of additional properties that can be used for `Screen` component:
#### `onDismiss`
#### `onDismissed`
A callback that gets called when the current screen is dismissed by hardware back (on Android) or dismiss gesture (swipe back or down). The callback takes no arguments.

View File

@@ -16,7 +16,7 @@ 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 class Screen extends ViewGroup {
public enum StackPresentation {
PUSH,
@@ -52,6 +52,7 @@ public class Screen extends ViewGroup implements ReactPointerEventsView {
private boolean mTransitioning;
private StackPresentation mStackPresentation = StackPresentation.PUSH;
private StackAnimation mStackAnimation = StackAnimation.DEFAULT;
private boolean mGestureEnabled = true;
public Screen(ReactContext context) {
super(context);
@@ -122,6 +123,10 @@ public class Screen extends ViewGroup implements ReactPointerEventsView {
mStackAnimation = stackAnimation;
}
public void setGestureEnabled(boolean gestureEnabled) {
mGestureEnabled = gestureEnabled;
}
public StackAnimation getStackAnimation() {
return mStackAnimation;
}
@@ -130,11 +135,6 @@ public class Screen extends ViewGroup implements ReactPointerEventsView {
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
@@ -169,4 +169,8 @@ public class Screen extends ViewGroup implements ReactPointerEventsView {
public boolean isActive() {
return mActive;
}
public boolean isGestureEnabled() {
return mGestureEnabled;
}
}

View File

@@ -25,7 +25,7 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
private final Set<ScreenFragment> mActiveScreenFragments = new HashSet<>();
private final ArrayList<Runnable> mAfterTransitionRunnables = new ArrayList<>(1);
private @Nullable FragmentManager mFragmentManager;
protected @Nullable FragmentManager mFragmentManager;
private @Nullable FragmentTransaction mCurrentTransaction;
private @Nullable FragmentTransaction mProcessingTransaction;
private boolean mNeedUpdate;
@@ -33,6 +33,7 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
private boolean mIsTransitioning;
private boolean mLayoutEnqueued = false;
private final ChoreographerCompat.FrameCallback mFrameCallback = new ChoreographerCompat.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
@@ -40,9 +41,9 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
}
};
private final Runnable mLayoutRunnable = new Runnable() {
private final ChoreographerCompat.FrameCallback mLayoutCallback = new ChoreographerCompat.FrameCallback() {
@Override
public void run() {
public void doFrame(long frameTimeNanos) {
mLayoutEnqueued = false;
measure(
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
@@ -66,9 +67,13 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
public void requestLayout() {
super.requestLayout();
if (!mLayoutEnqueued) {
if (!mLayoutEnqueued && mLayoutCallback != null) {
mLayoutEnqueued = true;
post(mLayoutRunnable);
// we use NATIVE_ANIMATED_MODULE choreographer queue because it allows us to catch the current
// looper loop instead of enqueueing the update in the next loop causing a one frame delay.
ReactChoreographer.getInstance().postFrameCallback(
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE,
mLayoutCallback);
}
}
@@ -184,16 +189,9 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
return ((FragmentActivity) context).getSupportFragmentManager();
}
protected final FragmentManager getFragmentManager() {
if (mFragmentManager == null) {
mFragmentManager = findFragmentManager();
}
return mFragmentManager;
}
protected FragmentTransaction getOrCreateTransaction() {
if (mCurrentTransaction == null) {
mCurrentTransaction = getFragmentManager().beginTransaction();
mCurrentTransaction = mFragmentManager.beginTransaction();
mCurrentTransaction.setReorderingAllowed(true);
}
return mCurrentTransaction;
@@ -243,24 +241,12 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
return mScreenFragments.contains(screenFragment);
}
protected void ensureFragmentManager() {
if (mFragmentManager != null && mFragmentManager.isDestroyed()) {
// When fragmentManager is destroyed, try to remove current fragment's views
for (int i = 0, size = mScreenFragments.size(); i < size; i++) {
ScreenFragment screenFragment = mScreenFragments.get(i);
removeView(screenFragment.getScreenRootView());
}
mFragmentManager = null;
mActiveScreenFragments.clear();
mNeedUpdate = true;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mIsAttached = true;
ensureFragmentManager();
mNeedUpdate = true;
mFragmentManager = findFragmentManager();
updateIfNeeded();
}
@@ -268,6 +254,14 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mIsAttached = false;
// fragment manager is destroyed so we can't do anything with it anymore
mFragmentManager = null;
// so we don't add the same screen twice after re-attach
removeAllViews();
mActiveScreenFragments.clear();
// after re-attach we'll update the screen and add views again
markUpdated();
}
@Override

View File

@@ -1,13 +1,11 @@
package com.swmansion.rnscreens;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
@@ -35,10 +33,6 @@ public class ScreenFragment extends Fragment {
return mScreenView;
}
protected ViewGroup getScreenRootView() {
return mScreenView;
}
public Screen getScreen() {
return mScreenView;
}

View File

@@ -22,7 +22,7 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
private final FragmentManager.OnBackStackChangedListener mBackStackListener = new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
if (mFragmentManager.getBackStackEntryCount() == 0) {
// when back stack entry count hits 0 it means the user's navigated back using hw back
// button. As the "fake" transaction we installed on the back stack does nothing we need
// to handle back navigation on our own.
@@ -70,24 +70,24 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
FragmentManager fm = getFragmentManager();
fm.removeOnBackStackChangedListener(mBackStackListener);
getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
if (!fm.isStateSaved()) {
// state save means that the container where fragment manager was installed has been unmounted.
// This could happen as a result of dismissing nested stack. In such a case we don't need to
// reset back stack as it'd result in a crash caused by the fact the fragment manager is no
// longer attached.
fm.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (mFragmentManager != null) {
mFragmentManager.removeOnBackStackChangedListener(mBackStackListener);
mFragmentManager.unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
if (!mFragmentManager.isStateSaved()) {
// state save means that the container where fragment manager was installed has been unmounted.
// This could happen as a result of dismissing nested stack. In such a case we don't need to
// reset back stack as it'd result in a crash caused by the fact the fragment manager is no
// longer attached.
mFragmentManager.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
super.onDetachedFromWindow();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks, false);
mFragmentManager.registerFragmentLifecycleCallbacks(mLifecycleCallbacks, false);
}
@Override
@@ -230,8 +230,8 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
// notified when it gets resumed so that we can install the handler.
return;
}
getFragmentManager().removeOnBackStackChangedListener(mBackStackListener);
getFragmentManager().popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
mFragmentManager.removeOnBackStackChangedListener(mBackStackListener);
mFragmentManager.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ScreenStackFragment firstScreen = null;
for (int i = 0, size = mStack.size(); i < size; i++) {
ScreenStackFragment screen = mStack.get(i);
@@ -241,14 +241,13 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
}
}
if (topScreen != firstScreen && topScreen.isDismissable()) {
getFragmentManager()
mFragmentManager
.beginTransaction()
.hide(topScreen)
.show(topScreen)
.addToBackStack(BACK_STACK_TAG)
.setPrimaryNavigationFragment(topScreen)
.commitAllowingStateLoss();
getFragmentManager().addOnBackStackChangedListener(mBackStackListener);
mFragmentManager.addOnBackStackChangedListener(mBackStackListener);
}
}
}

View File

@@ -96,16 +96,7 @@ public class ScreenStackFragment extends ScreenFragment {
return mScreenRootView;
}
@Override
protected ViewGroup getScreenRootView() {
return mScreenRootView;
}
public boolean isDismissable() {
View child = mScreenView.getChildAt(0);
if (child instanceof ScreenStackHeaderConfig) {
return ((ScreenStackHeaderConfig) child).isDismissable();
}
return true;
return mScreenView.isGestureEnabled();
}
}

View File

@@ -30,7 +30,6 @@ public class ScreenStackHeaderConfig extends ViewGroup {
private float mTitleFontSize;
private int mBackgroundColor;
private boolean mIsHidden;
private boolean mGestureEnabled = true;
private boolean mIsBackButtonHidden;
private boolean mIsShadowHidden;
private boolean mDestroyed;
@@ -51,6 +50,10 @@ public class ScreenStackHeaderConfig extends ViewGroup {
setVisibility(View.GONE);
mToolbar = new Toolbar(context);
// reset content insets to be 0 to allow react position custom navbar views. Note that this does
// not affect platform native back button as toolbar does not apply left inset when navigation
// button is specified
mToolbar.setContentInsetsAbsolute(0, 0);
// set primary color as background by default
TypedValue tv = new TypedValue();
@@ -111,10 +114,6 @@ public class ScreenStackHeaderConfig extends ViewGroup {
return null;
}
public boolean isDismissable() {
return mGestureEnabled;
}
public void onUpdate() {
Screen parent = (Screen) getParent();
final ScreenStack stack = getScreenStack();
@@ -299,10 +298,6 @@ public class ScreenStackHeaderConfig extends ViewGroup {
mIsShadowHidden = hideShadow;
}
public void setGestureEnabled(boolean gestureEnabled) {
mGestureEnabled = gestureEnabled;
}
public void setHideBackButton(boolean hideBackButton) {
mIsBackButtonHidden = hideBackButton;
}

View File

@@ -99,11 +99,6 @@ public class ScreenStackHeaderConfigViewManager extends ViewGroupManager<ScreenS
config.setHideShadow(hideShadow);
}
@ReactProp(name = "gestureEnabled", defaultBoolean = true)
public void setGestureEnabled(ScreenStackHeaderConfig config, boolean gestureEnabled) {
config.setGestureEnabled(gestureEnabled);
}
@ReactProp(name = "hideBackButton")
public void setHideBackButton(ScreenStackHeaderConfig config, boolean hideBackButton) {
config.setHideBackButton(hideBackButton);

View File

@@ -43,18 +43,15 @@ public class ScreenStackHeaderSubview extends ReactViewGroup {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed && (mType == Type.CENTER || mType == Type.TITLE)) {
if (changed && (mType == Type.CENTER)) {
// if we want the view to be centered we need to account for the fact that right and left
// paddings may not be equal.
Measurements measurements = new Measurements();
measurements.width = right - left;
if (mType == Type.CENTER) {
// if we want the view to be centered we need to account for the fact that right and left
// paddings may not be equal.
View parent = (View) getParent();
int parentWidth = parent.getWidth();
int rightPadding = parentWidth - right;
int leftPadding = left;
measurements.width = Math.max(0, parentWidth - 2 * Math.max(rightPadding, leftPadding));
}
View parent = (View) getParent();
int parentWidth = parent.getWidth();
int rightPadding = parentWidth - right;
int leftPadding = left;
measurements.width = Math.max(0, parentWidth - 2 * Math.max(rightPadding, leftPadding));
measurements.height = bottom - top;
mUIManager.setViewLocalData(getId(), measurements);
}

View File

@@ -57,6 +57,11 @@ public class ScreenViewManager extends ViewGroupManager<Screen> {
}
}
@ReactProp(name = "gestureEnabled", defaultBoolean = true)
public void setGestureEnabled(Screen view, boolean gestureEnabled) {
view.setGestureEnabled(gestureEnabled);
}
@Nullable
@Override
public Map getExportedCustomDirectEventTypeConstants() {

View File

@@ -75,7 +75,6 @@ class StackView extends React.Component {
headerBackTitleStyle && headerBackTitleStyle.fontFamily,
backTitleFontSize: headerBackTitleStyle && headerBackTitleStyle.fontSize,
color: headerTintColor,
gestureEnabled: gestureEnabled === undefined ? true : gestureEnabled,
largeTitle,
largeTitleFontFamily:
headerLargeTitleStyle && headerLargeTitleStyle.fontFamily,
@@ -191,6 +190,7 @@ class StackView extends React.Component {
style={options.cardStyle}
stackAnimation={stackAnimation}
stackPresentation={stackPresentation}
gestureEnabled={gestureEnabled === undefined ? true : gestureEnabled}
onAppear={() => this._onSceneFocus(route, descriptor)}
onDismissed={() => this._removeScene(route)}>
{this._renderHeaderConfig(index, route, descriptor)}

View File

@@ -44,6 +44,7 @@ typedef NS_ENUM(NSInteger, RNSScreenStackAnimation) {
@property (weak, nonatomic) UIView<RNSScreenContainerDelegate> *reactSuperview;
@property (nonatomic, retain) UIViewController *controller;
@property (nonatomic) BOOL active;
@property (nonatomic) BOOL gestureEnabled;
@property (nonatomic) RNSScreenStackAnimation stackAnimation;
@property (nonatomic) RNSScreenStackPresentation stackPresentation;

View File

@@ -26,6 +26,7 @@
_controller = [[RNSScreen alloc] initWithView:self];
_stackPresentation = RNSScreenStackPresentationPush;
_stackAnimation = RNSScreenStackAnimationDefault;
_gestureEnabled = YES;
}
return self;
@@ -276,6 +277,7 @@
RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(active, BOOL)
RCT_EXPORT_VIEW_PROPERTY(gestureEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(stackPresentation, RNSScreenStackPresentation)
RCT_EXPORT_VIEW_PROPERTY(stackAnimation, RNSScreenStackAnimation)
RCT_EXPORT_VIEW_PROPERTY(onAppear, RCTDirectEventBlock);

View File

@@ -102,16 +102,9 @@
RCTRootContentView *rootView = (RCTRootContentView *)parent;
[rootView.touchHandler cancel];
UIView *topView = _controller.viewControllers.lastObject.view;
RNSScreenStackHeaderConfig *config = nil;
for (UIView *subview in topView.reactSubviews) {
if ([subview isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
config = (RNSScreenStackHeaderConfig*) subview;
break;
}
}
RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view;
return _controller.viewControllers.count > 1 && (config == nil || config.gestureEnabled);
return _controller.viewControllers.count > 1 && topScreen.gestureEnabled;
}
- (void)markChildUpdated

View File

@@ -23,7 +23,6 @@
@property (nonatomic) BOOL hideBackButton;
@property (nonatomic) BOOL hideShadow;
@property (nonatomic) BOOL translucent;
@property (nonatomic) BOOL gestureEnabled;
+ (void)willShowViewController:(UIViewController *)vc withConfig:(RNSScreenStackHeaderConfig*)config;

View File

@@ -60,7 +60,6 @@
self.hidden = YES;
_translucent = YES;
_reactSubviews = [NSMutableArray new];
_gestureEnabled = YES;
}
return self;
}
@@ -269,7 +268,7 @@
[navctr setNavigationBarHidden:shouldHide animated:YES];
#ifdef __IPHONE_13_0
if (@available(iOS 13.0, *)) {
vc.modalInPresentation = !config.gestureEnabled;
vc.modalInPresentation = !config.screenView.gestureEnabled;
}
#endif
if (shouldHide) {
@@ -454,7 +453,6 @@ RCT_EXPORT_VIEW_PROPERTY(hideShadow, BOOL)
// `hidden` is an UIView property, we need to use different name internally
RCT_REMAP_VIEW_PROPERTY(hidden, hide, BOOL)
RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL)
RCT_EXPORT_VIEW_PROPERTY(gestureEnabled, BOOL)
@end

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-screens",
"version": "2.0.0-alpha.25",
"version": "2.0.0-alpha.30",
"description": "First incomplete navigation solution for your react-native app.",
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",

View File

@@ -1741,10 +1741,10 @@ commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commondir@^1.0.1:
version "1.0.1"
@@ -2765,9 +2765,9 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
handlebars@^4.0.3:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
version "4.5.3"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
@@ -5855,11 +5855,11 @@ uglify-es@^3.1.9:
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
version "3.7.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a"
integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==
dependencies:
commander "~2.20.0"
commander "~2.20.3"
source-map "~0.6.1"
ultron@1.0.x: