Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e0b6c5c
Put back shared elements array code
grahammendick Jun 3, 2023
e122c94
Got zoom sample working with original shared el
grahammendick Jun 4, 2023
791e4c8
Made both view and child shareable elements
grahammendick Jun 4, 2023
de0d7c1
Added func that returns transition from shared el
grahammendick Jun 4, 2023
9ccf24d
Passed shared els in one prop to native
grahammendick Jun 4, 2023
8e62425
Indicated whether to use old or new transition
grahammendick Jun 4, 2023
e3ab829
Got it working for container transform
grahammendick Jun 4, 2023
fcc66a1
Ignored duration if default
grahammendick Jun 4, 2023
cede7aa
Faded the enter/exit scenes when shared elements
grahammendick Jun 9, 2023
8d1b58b
Prevented waiting forever
grahammendick Jun 9, 2023
246635f
Ensured rested after shared element transition
grahammendick Jun 9, 2023
b80eeb7
Removed redundant imports
grahammendick Jun 9, 2023
21b9cc5
Increased timeout postpone waits for
grahammendick Jun 9, 2023
edacce0
Ensured onRest only called for entering scene
grahammendick Jun 10, 2023
5c78326
Revert "Ensured onRest only called for entering scene"
grahammendick Jun 10, 2023
759a0bd
Revert "Increased timeout postpone waits for"
grahammendick Jun 10, 2023
e875aca
Revert "Removed redundant imports"
grahammendick Jun 10, 2023
938b647
Revert "Ensured rested after shared element transition"
grahammendick Jun 10, 2023
2838bab
Revert "Faded the enter/exit scenes when shared elements"
grahammendick Jun 10, 2023
a635870
Reverted accidental commit
grahammendick Jun 10, 2023
dae52dc
Ensured onRest called when shared elements
grahammendick Jun 10, 2023
5285b78
Removed redundant spaces
grahammendick Jun 11, 2023
b2dedb5
Ensured can dynamically change shared element
grahammendick Jun 11, 2023
f6ad578
Supported swapping shared element children
grahammendick Jun 11, 2023
7d3c437
Tweaked format
grahammendick Jun 11, 2023
93d80bc
Typed sharedElements prop of NavigationStack
grahammendick Jun 11, 2023
b6504ad
Copied over shared element changes to fabric
grahammendick Jun 11, 2023
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
18 changes: 11 additions & 7 deletions NavigationReactNative/src/NavigationStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { StateNavigator, Crumb, State } from 'navigation';
import { NavigationContext } from 'navigation-react';
import PopSync from './PopSync';
import Scene from './Scene';
type NavigationStackProps = {underlayColor: string, title: (state: State, data: any) => string, crumbStyle: any, unmountStyle: any, hidesTabBar: any, sharedElement: any, backgroundColor: any, stackInvalidatedLink: string, renderScene: (state: State, data: any) => ReactNode, children: any};
type NavigationStackProps = {underlayColor: string, title: (state: State, data: any) => string, crumbStyle: any, unmountStyle: any, hidesTabBar: any, sharedElement: any, sharedElements: any, backgroundColor: any, stackInvalidatedLink: string, renderScene: (state: State, data: any) => ReactNode, children: any};
type NavigationStackState = {stateNavigator: StateNavigator, keys: string[], rest: boolean, counter: number, mostRecentEventCount: number};

const NavigationStack = ({underlayColor = '#000', title, crumbStyle: crumbStyleStack = () => null, unmountStyle: unmountStyleStack = () => null,
hidesTabBar: hidesTabBarStack = () => false, sharedElement: getSharedElementStack = () => null, backgroundColor: backgroundColorStack = () => null,
hidesTabBar: hidesTabBarStack = () => false, sharedElement: getSharedElementStack = () => null, sharedElements: getSharedElementsStack = () => null,
backgroundColor: backgroundColorStack = () => null,
stackInvalidatedLink, renderScene, children}: NavigationStackProps) => {
const resumeNavigationRef = useRef(null);
const ref = useRef(null);
Expand Down Expand Up @@ -74,32 +75,35 @@ const NavigationStack = ({underlayColor = '#000', title, crumbStyle: crumbStyleS
const crumbStyle = (from, state, ...rest) => sceneProps(state)?.crumbStyle ? sceneProps(state)?.crumbStyle(from, ...rest) : crumbStyleStack(from, state, ...rest);
const hidesTabBar = (state, ...rest) => sceneProps(state)?.hidesTabBar ? returnOrCall(sceneProps(state)?.hidesTabBar, ...rest) : hidesTabBarStack(state, ...rest);
const getSharedElement = (state, ...rest) => sceneProps(state)?.sharedElement ? returnOrCall(sceneProps(state)?.sharedElement, ...rest) : getSharedElementStack(state, ...rest);
const getSharedElements = (state, ...rest) => sceneProps(state)?.sharedElements ? returnOrCall(sceneProps(state)?.sharedElements, ...rest) : getSharedElementsStack(state, ...rest);
const backgroundColor = (state, ...rest) => sceneProps(state)?.backgroundColor ? returnOrCall(sceneProps(state)?.backgroundColor, ...rest) : backgroundColorStack(state, ...rest);
const getAnimation = () => {
let {state, data, oldState, oldData, oldUrl, crumbs, nextCrumb} = stateNavigator.stateContext;
if (!oldState)
return null;
const {crumbs: oldCrumbs} = stateNavigator.parseLink(oldUrl);
let enterAnim, exitAnim, sharedElement, oldSharedElement;
let enterAnim, exitAnim, sharedElements;
if (oldCrumbs.length < crumbs.length) {
const {state: nextState, data: nextData} = crumbs.concat(nextCrumb)[oldCrumbs.length + 1];
enterAnim = unmountStyle(true, state, data, crumbs);
exitAnim = crumbStyle(false, oldState, oldData, oldCrumbs, nextState, nextData);
sharedElement = getSharedElement(state, data, crumbs);
sharedElements = getSharedElement(state, data, crumbs) || getSharedElements(state, data, crumbs);
}
if (crumbs.length < oldCrumbs.length) {
nextCrumb = new Crumb(oldData, oldState, null, null, false);
const {state: nextState, data: nextData} = oldCrumbs.concat(nextCrumb)[crumbs.length + 1];
enterAnim = crumbStyle(true, state, data, crumbs, nextState, nextData);
exitAnim = unmountStyle(false, oldState, oldData, oldCrumbs);
oldSharedElement = getSharedElement(oldState, oldData, oldCrumbs);
sharedElements = getSharedElement(oldState, oldData, oldCrumbs) || getSharedElements(oldState, oldData, oldCrumbs);
}
if (crumbs.length === oldCrumbs.length) {
enterAnim = unmountStyle(true, state, data, crumbs);
exitAnim = unmountStyle(false, oldState, oldData, oldCrumbs, state, data);
}
var enterAnimOff = enterAnim === '';
return {enterAnim, exitAnim, enterAnimOff, sharedElement, oldSharedElement};
const containerTransform = typeof sharedElements === 'string';
sharedElements = containerTransform && sharedElements ? [sharedElements] : sharedElements;
const enterAnimOff = enterAnim === '';
return {enterAnim, exitAnim, enterAnimOff, sharedElements, containerTransform};
}
const {stateNavigator: prevStateNavigator, keys, rest, mostRecentEventCount} = stackState;
if (prevStateNavigator !== stateNavigator && stateNavigator.stateContext.state) {
Expand Down
4 changes: 2 additions & 2 deletions NavigationReactNative/src/NavigationStackNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ type NativeProps = $ReadOnly<{|
enterAnim: string,
exitAnim: string,
enterAnimOff: boolean,
sharedElement: string,
oldSharedElement: string,
sharedElements: $ReadOnlyArray<string>,
containerTransform: boolean,
mostRecentEventCount: Int32,
onNavigateToTop: DirectEventHandler<null>,
onWillNavigateBack: DirectEventHandler<$ReadOnly<{|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ public void setExitAnim(NavigationStackView view, String exitAnim) {
view.exitAnim = exitAnim;
}

@ReactProp(name = "sharedElement")
public void setSharedElement(NavigationStackView view, String sharedElement) {
view.sharedElementName = sharedElement;
@ReactProp(name = "sharedElements")
public void setSharedElements(NavigationStackView view, ReadableArray sharedElements) {
view.sharedElementNames = sharedElements;
}

@ReactProp(name = "oldSharedElement")
public void setOldSharedElement(NavigationStackView view, String oldSharedElement) {
view.oldSharedElementName = oldSharedElement;
@ReactProp(name = "containerTransform")
public void setContainerTransform(NavigationStackView view, boolean containerTransform) {
view.containerTransform = containerTransform;
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

Expand All @@ -49,9 +50,9 @@ public class NavigationStackView extends ViewGroup implements LifecycleEventList
private Activity mainActivity;
protected String enterAnim;
protected String exitAnim;
protected String sharedElementName;
protected String oldSharedElementName;
protected ReadableArray sharedElementNames;
protected Boolean startNavigation = null;
protected boolean containerTransform = false;

public NavigationStackView(Context context) {
super(context);
Expand Down Expand Up @@ -99,10 +100,10 @@ protected void onAfterUpdateTransaction() {
if (crumb < currentCrumb) {
FragmentManager fragmentManager = fragment.getChildFragmentManager();
SceneFragment fragment = (SceneFragment) fragmentManager.findFragmentByTag(oldKey);
Pair<SharedElementView, String> sharedElement = fragment != null ? getOldSharedElement(currentCrumb, crumb, fragment) : null;
Pair[] sharedElements = fragment != null ? getOldSharedElements(currentCrumb, crumb, fragment) : null;
SceneFragment prevFragment = (SceneFragment) fragmentManager.findFragmentByTag(keys.getString(crumb));
if (sharedElement != null && prevFragment != null && prevFragment.getScene() != null)
prevFragment.getScene().sharedElementMotion = new SharedElementMotion(fragment, prevFragment, oldSharedElementName);
if (sharedElements != null && prevFragment != null && prevFragment.getScene() != null)
prevFragment.getScene().sharedElementMotion = new SharedElementMotion(fragment, prevFragment, getSharedElementSet(sharedElementNames), containerTransform);
fragmentManager.popBackStack(String.valueOf(crumb), 0);
}
if (crumb > currentCrumb) {
Expand All @@ -120,18 +121,21 @@ protected void onAfterUpdateTransaction() {
int popExit = getAnimationResourceId(currentActivity, scene.exitAnim, android.R.attr.activityCloseExitAnimation);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setReorderingAllowed(true);
Pair<SharedElementView, String> sharedElement = null;
Pair[] sharedElements = null;
if (nextCrumb > 0) {
String prevKey = keys.getString(nextCrumb - 1);
SceneFragment prevFragment = (SceneFragment) fragmentManager.findFragmentByTag(prevKey);
if (prevFragment != null)
sharedElement = getSharedElement(currentCrumb, crumb, prevFragment);
sharedElements = getSharedElements(currentCrumb, crumb, prevFragment);
}
if (sharedElement != null) {
fragmentTransaction.addSharedElement(sharedElement.first, sharedElement.second);
if (sharedElements != null) {
for(Pair sharedElement : sharedElements) {
SharedElementView sharedEl = (SharedElementView) sharedElement.first;
fragmentTransaction.addSharedElement(containerTransform ? sharedEl : sharedEl.getChildAt(0), (containerTransform ? "" : "element__") + sharedElement.second);
}
}
fragmentTransaction.setCustomAnimations(oldCrumb != -1 ? enter : 0, exit, popEnter, popExit);
SceneFragment fragment = new SceneFragment(scene, sharedElementName);
fragmentTransaction.setCustomAnimations(oldCrumb != -1 && sharedElements == null ? enter : 0, exit, sharedElements == null ? popEnter : 0, popExit);
SceneFragment fragment = new SceneFragment(scene, getSharedElementSet(sharedElementNames), containerTransform);
fragmentTransaction.replace(getId(), fragment, key);
fragmentTransaction.addToBackStack(String.valueOf(nextCrumb));
fragmentTransaction.commit();
Expand All @@ -149,7 +153,7 @@ protected void onAfterUpdateTransaction() {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.setCustomAnimations(enter, exit, popEnter, popExit);
fragmentTransaction.replace(getId(), new SceneFragment(scene, null), key);
fragmentTransaction.replace(getId(), new SceneFragment(scene, null, containerTransform), key);
fragmentTransaction.addToBackStack(String.valueOf(crumb));
fragmentTransaction.commit();
}
Expand All @@ -166,6 +170,16 @@ int getAnimationResourceId(Context context, String animationName, int defaultId)
return context.getResources().getIdentifier(animationName, "anim", packageName);
}

HashSet<String> getSharedElementSet(ReadableArray sharedElementNames) {
if (sharedElementNames == null)
return null;
HashSet<String> sharedElementSet = new HashSet<>();
for(int i = 0; i < sharedElementNames.size(); i++) {
sharedElementSet.add(sharedElementNames.getString(i));
}
return sharedElementSet;
}

HashMap<String, SharedElementView> getSharedElementMap(SceneView scene) {
HashMap<String, SharedElementView> sharedElementMap = new HashMap<>();
for(SharedElementView sharedElement : scene.sharedElements) {
Expand All @@ -174,45 +188,58 @@ HashMap<String, SharedElementView> getSharedElementMap(SceneView scene) {
return sharedElementMap;
}

Pair<SharedElementView, String> getSharedElement(HashMap<String, SharedElementView> sharedElementMap, String sharedElementName) {
if (sharedElementMap == null || sharedElementName == null)
Pair[] getSharedElements(HashMap<String, SharedElementView> sharedElementMap, ReadableArray sharedElementNames) {
if (sharedElementMap == null || sharedElementNames == null)
return null;
if (sharedElementMap.containsKey(sharedElementName))
return Pair.create(sharedElementMap.get(sharedElementName), sharedElementName);
return null;
ArrayList<Pair> sharedElementPairs = new ArrayList<>();
for(int i = 0; i < sharedElementNames.size(); i++) {
String name = sharedElementNames.getString(i);
if (sharedElementMap.containsKey(name))
sharedElementPairs.add(Pair.create(sharedElementMap.get(name), name));
}
return sharedElementPairs.toArray(new Pair[0]);
}

private Pair<SharedElementView, String> getOldSharedElement(int currentCrumb, int crumb, SceneFragment sceneFragment) {
private Pair[] getOldSharedElements(int currentCrumb, int crumb, SceneFragment sceneFragment) {
final HashMap<String, SharedElementView> oldSharedElementsMap = getSharedElementMap(sceneFragment.getScene());
final Pair<SharedElementView, String> oldSharedElement = currentCrumb - crumb == 1 ? getSharedElement(oldSharedElementsMap, oldSharedElementName) : null;
if (oldSharedElement != null) {
final Pair[] oldSharedElements = currentCrumb - crumb == 1 ? getSharedElements(oldSharedElementsMap, sharedElementNames) : null;
if (oldSharedElements != null && oldSharedElements.length != 0) {
sceneFragment.setEnterSharedElementCallback(new SharedElementCallback() {
@Override
public void onMapSharedElements(List<String> names, Map<String, View> elements) {
if (oldSharedElementsMap.containsKey(oldSharedElementName)) {
View oldSharedElement = oldSharedElementsMap.get(oldSharedElementName);
elements.put(names.get(0), oldSharedElement);
for(int i = 0; i < sharedElementNames.size(); i++) {
String name = sharedElementNames.getString(i);
if (oldSharedElementsMap.containsKey(name)) {
SharedElementView oldSharedElement = oldSharedElementsMap.get(name);
elements.put(names.get(i), containerTransform ? oldSharedElement : oldSharedElement.getChildAt(0));
}
}
}
});
return oldSharedElement;
return oldSharedElements;
}
return null;
}

private Pair<SharedElementView, String> getSharedElement(int currentCrumb, int crumb, SceneFragment sceneFragment) {
private Pair[] getSharedElements(int currentCrumb, int crumb, SceneFragment sceneFragment) {
final HashMap<String, SharedElementView> sharedElementsMap = getSharedElementMap(sceneFragment.getScene());
final Pair<SharedElementView, String> sharedElement = crumb - currentCrumb == 1 ? getSharedElement(sharedElementsMap, sharedElementName) : null;
if (sharedElement != null) {
final Pair[] sharedElements = crumb - currentCrumb == 1 ? getSharedElements(sharedElementsMap, sharedElementNames) : null;
if (sharedElements != null && sharedElements.length != 0) {
sceneFragment.setExitSharedElementCallback(new SharedElementCallback() {
@Override
public void onMapSharedElements(List<String> names, Map<String, View> elements) {
String mappedName = oldSharedElementName != null ? oldSharedElementName : names.get(0);
if (sharedElementsMap.containsKey(mappedName))
elements.put(names.get(0), sharedElementsMap.get(mappedName));
for(int i = 0; i < names.size(); i++) {
String mappedName = names.get(i);
if (sharedElementNames != null && sharedElementNames.size() > i)
mappedName = sharedElementNames.getString(i);
if (sharedElementsMap.containsKey(mappedName)) {
SharedElementView sharedElement = sharedElementsMap.get(mappedName);
elements.put(names.get(i), containerTransform ? sharedElement : sharedElement.getChildAt(0));
}
}
}
});
return sharedElement;
return sharedElements;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ public void setExitAnim(NavigationStackView view, String exitAnim) {
view.exitAnim = exitAnim;
}

@ReactProp(name = "sharedElement")
public void setSharedElement(NavigationStackView view, String sharedElement) {
view.sharedElementName = sharedElement;
@ReactProp(name = "sharedElements")
public void setSharedElements(NavigationStackView view, ReadableArray sharedElements) {
view.sharedElementNames = sharedElements;
}

@ReactProp(name = "oldSharedElement")
public void setOldSharedElement(NavigationStackView view, String oldSharedElement) {
view.oldSharedElementName = oldSharedElement;
@ReactProp(name = "containerTransform")
public void setContainerTransform(NavigationStackView view, boolean containerTransform) {
view.containerTransform = containerTransform;
}

@ReactProp(name = "mostRecentEventCount")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

public class SceneFragment extends Fragment {
private SceneView scene;

public SceneFragment() {
super();
}

SceneFragment(SceneView scene, String sharedElement) {
SceneFragment(SceneView scene, HashSet<String> sharedElements, boolean containerTransform) {
super();
this.scene = scene;
if (sharedElement != null )
scene.sharedElementMotion = new SharedElementMotion(this, this, sharedElement);
if (sharedElements != null )
scene.sharedElementMotion = new SharedElementMotion(this, this, sharedElements, containerTransform);
}

@Nullable
Expand All @@ -33,7 +36,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
if (scene.getParent() != null)
((ViewGroup) scene.getParent()).endViewTransition(scene);
if (scene.sharedElementMotion != null)
postponeEnterTransition();
postponeEnterTransition(300, TimeUnit.MILLISECONDS);
return scene;
}
return new View(getContext());
Expand Down
Loading