Skip to content

Commit

Permalink
[Shared Element Transition] Problem with headers (#4036)
Browse files Browse the repository at this point in the history
## Summary

PR contains improvements in snapshotting view properties. 
- Android - Now animation will start when the screen has an attached
header. In effect, the values in the snapshot will be valid.
- iOS - I replaced the old approach by detecting the screen header and
adding information about header size to the snapshot.
  • Loading branch information
piaskowyk authored Feb 10, 2023
1 parent 22c130b commit 8209bfb
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,6 @@ private View findStack(View view) {

protected void makeSnapshot(View view) {
Snapshot snapshot = new Snapshot(view);
View screen = findScreen(view);
if (screen != null) {
snapshot.originY -= screen.getTop();
}
mSnapshotRegistry.put(view.getId(), snapshot);
}

Expand Down Expand Up @@ -408,7 +404,9 @@ void visitNativeTreeAndMakeSnapshot(View view) {
return;
}
ViewGroup viewGroup = (ViewGroup) view;
makeSnapshot(view);
if (mAnimationsManager.hasAnimationForTag(view.getId(), "sharedElementTransition")) {
makeSnapshot(view);
}
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
visitNativeTreeAndMakeSnapshot(child);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,30 @@ public synchronized void updateLayout(
if (container != null
&& viewManagerName.equals("RNSScreen")
&& mReaLayoutAnimator != null) {
((ReaLayoutAnimator) mReaLayoutAnimator).getAnimationsManager().viewsDidLayout();
boolean hasHeader = checkIfTopScreenHasHeader((ViewGroup) container);
if (!hasHeader || !container.isLayoutRequested()) {
mReaLayoutAnimator.getAnimationsManager().viewsDidLayout();
}
}
} catch (IllegalViewOperationException e) {
// (IllegalViewOperationException) == (vm == null)
e.printStackTrace();
}
}

private boolean checkIfTopScreenHasHeader(ViewGroup screenStack) {
try {
ViewGroup fragment = (ViewGroup)screenStack.getChildAt(0);
ViewGroup screen = (ViewGroup)fragment.getChildAt(0);
View headerConfig = screen.getChildAt(0);
Field field = headerConfig.getClass().getDeclaredField("mIsHidden");
field.setAccessible(true);
return !field.getBoolean(headerConfig);
} catch (NullPointerException | NoSuchFieldException | IllegalAccessException e) {
return false;
}
}

@Override
public synchronized void manageChildren(
int tag,
Expand Down
4 changes: 3 additions & 1 deletion ios/LayoutReanimation/REASharedTransitionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,9 @@ - (void)finishSharedAnimation:(UIView *)view
BOOL isScreenDetached = [self getScreenForView:view].superview == nil;
NSNumber *originY = viewSourcePreviousSnapshot.values[@"originY"];
if (isScreenDetached) {
viewSourcePreviousSnapshot.values[@"originY"] = viewSourcePreviousSnapshot.values[@"originYByParent"];
float originYByParent = [viewSourcePreviousSnapshot.values[@"originYByParent"] floatValue];
float headerHeight = [viewSourcePreviousSnapshot.values[@"headerHeight"] floatValue];
viewSourcePreviousSnapshot.values[@"originY"] = @(originYByParent + headerHeight);
}
[_animationManager progressLayoutAnimationWithStyle:viewSourcePreviousSnapshot.values
forTag:view.reactTag
Expand Down
9 changes: 9 additions & 0 deletions ios/LayoutReanimation/REASnapshot.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import <Foundation/Foundation.h>
#import <RNReanimated/REASnapshot.h>
#import <React/UIView+React.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -34,6 +35,14 @@ - (void)makeSnapshotForView:(UIView *)view useAbsolutePositionOnly:(BOOL)useAbso
_values[@"originX"] = _values[@"globalOriginX"];
_values[@"originY"] = _values[@"globalOriginY"];
_values[@"originYByParent"] = [NSNumber numberWithDouble:view.center.y - view.bounds.size.height / 2.0];

UIView *navigationContainer = view.reactViewController.navigationController.view;
UIView *header = [navigationContainer.subviews count] > 1 ? navigationContainer.subviews[1] : nil;
if (header != nil) {
_values[@"headerHeight"] = @(header.frame.size.height);
} else {
_values[@"headerHeight"] = @(0);
}
} else {
_values[@"originX"] = [NSNumber numberWithDouble:view.center.x - view.bounds.size.width / 2.0];
_values[@"originY"] = [NSNumber numberWithDouble:view.center.y - view.bounds.size.height / 2.0];
Expand Down

0 comments on commit 8209bfb

Please sign in to comment.