mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-29 22:42:59 +08:00
Appear event is used by react-navigation to properly dispatch focus. It is important that appear is dispatched after dismissed event. The reverse order of actions would result in getting react-navigation stack in a weird state. It is relatively streightforward to implement onAppear event on iOS where we hook into didAppear callback from UIViewController. It gets dispatched in the right moment, that is when the transition is fully over. On Android however it is much more tricky. There is no standard way to be notified from the fragment level that fragment transition finished. One way that is frequently recommended is to override Fragment.onCreateAnimation. However, this only works when custom transitions are provided (e.g. if we set the transition to use fade animation). As we want the platform native transition to be run by default we had to look for other ways. The current approach relies on fragment container's callbacks startViewTransition and endViewTransition, with the latter being triggered once the animation is over. We also need to take into account that a good starting point for the transition is when we call commit on fragment transaction. We use these two methods to determine if the fragment is instantiated (onCreate) within a running transaction and if so we schedule event dispatch at the moment when endViewTransition is called. Another change this commit introduces on the Android side is that we no longer rely on show/hide for replacing fragments on stack and we now use add/remove transaction methods. Due to this change we had to make our fragments reusable and make onCreateView indempotent.
107 lines
3.4 KiB
Java
107 lines
3.4 KiB
Java
package com.swmansion.rnscreens;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.graphics.Color;
|
|
import android.os.Bundle;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.LinearLayout;
|
|
|
|
import androidx.annotation.Nullable;
|
|
import androidx.appcompat.widget.Toolbar;
|
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
|
|
import com.facebook.react.uimanager.PixelUtil;
|
|
import com.google.android.material.appbar.AppBarLayout;
|
|
|
|
public class ScreenStackFragment extends ScreenFragment {
|
|
|
|
private static final float TOOLBAR_ELEVATION = PixelUtil.toPixelFromDIP(4);
|
|
|
|
private AppBarLayout mAppBarLayout;
|
|
private Toolbar mToolbar;
|
|
private boolean mShadowHidden;
|
|
private CoordinatorLayout mScreenRootView;
|
|
|
|
@SuppressLint("ValidFragment")
|
|
public ScreenStackFragment(Screen screenView) {
|
|
super(screenView);
|
|
}
|
|
|
|
public void removeToolbar() {
|
|
if (mAppBarLayout != null) {
|
|
((CoordinatorLayout) getView()).removeView(mAppBarLayout);
|
|
}
|
|
}
|
|
|
|
public void setToolbar(Toolbar toolbar) {
|
|
if (mAppBarLayout != null) {
|
|
mAppBarLayout.addView(toolbar);
|
|
}
|
|
mToolbar = toolbar;
|
|
AppBarLayout.LayoutParams params = new AppBarLayout.LayoutParams(
|
|
AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT);
|
|
params.setScrollFlags(0);
|
|
mToolbar.setLayoutParams(params);
|
|
}
|
|
|
|
public void setToolbarShadowHidden(boolean hidden) {
|
|
if (mShadowHidden != hidden) {
|
|
mAppBarLayout.setTargetElevation(hidden ? 0 : TOOLBAR_ELEVATION);
|
|
mShadowHidden = hidden;
|
|
}
|
|
}
|
|
|
|
public void onStackUpdate() {
|
|
View child = mScreenView.getChildAt(0);
|
|
if (child instanceof ScreenStackHeaderConfig) {
|
|
((ScreenStackHeaderConfig) child).onUpdate();
|
|
}
|
|
}
|
|
|
|
private CoordinatorLayout configureView() {
|
|
CoordinatorLayout view = new CoordinatorLayout(getContext());
|
|
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
|
|
params.setBehavior(new AppBarLayout.ScrollingViewBehavior());
|
|
mScreenView.setLayoutParams(params);
|
|
view.addView(mScreenView);
|
|
|
|
mAppBarLayout = new AppBarLayout(getContext());
|
|
// By default AppBarLayout will have a background color set but since we cover the whole layout
|
|
// with toolbar (that can be semi-transparent) the bar layout background color does not pay a
|
|
// role. On top of that it breaks screens animations when alfa offscreen compositing is off
|
|
// (which is the default)
|
|
mAppBarLayout.setBackgroundColor(Color.TRANSPARENT);
|
|
mAppBarLayout.setLayoutParams(new AppBarLayout.LayoutParams(
|
|
AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT));
|
|
view.addView(mAppBarLayout);
|
|
|
|
if (mToolbar != null) {
|
|
mAppBarLayout.addView(mToolbar);
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater,
|
|
@Nullable ViewGroup container,
|
|
@Nullable Bundle savedInstanceState) {
|
|
if (mScreenRootView == null) {
|
|
mScreenRootView = configureView();
|
|
}
|
|
|
|
return mScreenRootView;
|
|
}
|
|
|
|
public boolean isDismissable() {
|
|
View child = mScreenView.getChildAt(0);
|
|
if (child instanceof ScreenStackHeaderConfig) {
|
|
return ((ScreenStackHeaderConfig) child).isDismissable();
|
|
}
|
|
return true;
|
|
}
|
|
}
|