Skip to content

Commit

Permalink
fix(ios): fixed image stretching/detection on RN60
Browse files Browse the repository at this point in the history
  • Loading branch information
IjzerenHein committed Jan 7, 2020
1 parent ef8c440 commit 8571cc5
Showing 1 changed file with 121 additions and 50 deletions.
171 changes: 121 additions & 50 deletions ios/RNSharedElementNode.m
Expand Up @@ -4,9 +4,33 @@
//

#import <UIKit/UIKit.h>
#import <React/RCTView.h>
#import "RNSharedElementNode.h"
#import "RNSharedElementContent.h"

@interface RNSharedElementNodeResolvedSource : NSObject
@property (nonatomic, readonly) UIView* view;
@property (nonatomic, readonly) BOOL hasChildImageView;
- (instancetype)initWithView:(UIView*) view hasChildImageView:(BOOL)hasChildImageView;
@end
@implementation RNSharedElementNodeResolvedSource
- (instancetype)initWithView:(UIView*) view hasChildImageView:(BOOL)hasChildImageView
{
_view = view;
_hasChildImageView = hasChildImageView;
return self;
}
+ (instancetype)sourceWithView:(UIView*) view {
return [[RNSharedElementNodeResolvedSource alloc]initWithView:view hasChildImageView:NO];
}
+ (instancetype)sourceWithView:(UIView*) view hasChildImageView:(BOOL)hasChildImageView {
return [[RNSharedElementNodeResolvedSource alloc]initWithView:view hasChildImageView:hasChildImageView];
}
- (UIView*) contentView {
return (_hasChildImageView && _view.subviews.count) ? _view.subviews[0] : _view;
}
@end

@implementation RNSharedElementNode
{
long _refCount;
Expand All @@ -22,7 +46,7 @@ @implementation RNSharedElementNode
CADisplayLink* _displayLink;

__weak UIView* _sourceView;
UIView * _view;
RNSharedElementNodeResolvedSource* _resolvedSource;
}

@synthesize reactTag = _reactTag;
Expand All @@ -47,38 +71,54 @@ - (instancetype)init:(NSNumber *)reactTag view:(UIView*) view isParent:(BOOL)isP
_styleRequests = nil;
_styleCache = nil;
_displayLink = nil;
self.view = [RNSharedElementNode resolveView:_isParent ? _sourceView.subviews.firstObject : _sourceView];
if (_isParent) [self addContentObservers:_sourceView];
_resolvedSource = [RNSharedElementNodeResolvedSource sourceWithView:nil];
[self updateResolvedSource:YES];
if (_isParent) [self addStyleObservers:_sourceView];
return self;
}

- (UIView*) view
{
return _view;
return _resolvedSource ? _resolvedSource.view : nil;
}

- (void) setView:(UIView*) view
- (void) updateResolvedSource:(BOOL)noReset
{
if (_view == view) return;
RNSharedElementNodeResolvedSource* resolvedSource = noReset
? [RNSharedElementNode resolveSource:_isParent ? _sourceView.subviews.firstObject : _sourceView]
: [RNSharedElementNodeResolvedSource sourceWithView:nil];

if ((_resolvedSource.view == resolvedSource.view) && (_resolvedSource.contentView == resolvedSource.contentView)) return;

if (_view != nil) {
if (_hideRefCount) _view.hidden = NO;
[self removeContentObservers: _view];
// Remove old observers
if (_resolvedSource.view != nil && _resolvedSource.view != resolvedSource.view) {
if (_hideRefCount) _resolvedSource.view.hidden = NO;
[self removeStyleObservers: _resolvedSource.view];
}
_view = view;
if (_view != nil) {
if (_hideRefCount) _view.hidden = YES;
[self addContentObservers:_view];
if (_resolvedSource.contentView != nil && _resolvedSource.contentView != resolvedSource.contentView) {
[self removeContentObservers: _resolvedSource.contentView];
}

// Add new observers
if (resolvedSource.view != nil && _resolvedSource.view != resolvedSource.view) {
if (_hideRefCount) resolvedSource.view.hidden = YES;
[self addStyleObservers:resolvedSource.view];
}
if (resolvedSource.contentView != nil && _resolvedSource.contentView != resolvedSource.contentView) {
[self addContentObservers:resolvedSource.contentView];
}

// Update resolved source
_resolvedSource = resolvedSource;
}

+ (UIView*) resolveView:(UIView*) view
+ (RNSharedElementNodeResolvedSource*) resolveSource:(UIView*) view
{
if (view == nil || _imageResolvers == nil) return view;

if (view == nil || _imageResolvers == nil) return [RNSharedElementNodeResolvedSource sourceWithView:view];
// If the view is an ImageView, then use that.
if ([RNSharedElementContent isKindOfImageView:view]) {
return view;
return [RNSharedElementNodeResolvedSource sourceWithView:view];
}

// In case the view contains a single UIImageView child
Expand All @@ -89,8 +129,20 @@ + (UIView*) resolveView:(UIView*) view
if (subview.subviews.count != 1) break;
subview = subview.subviews.firstObject;
if ([RNSharedElementContent isKindOfImageView:subview]) {
if (CGRectEqualToRect(subview.frame, view.bounds)) {
return subview;
CGRect bounds = view.bounds;
if ([view isKindOfClass:[RCTView class]]) {
RCTView* rctView = (RCTView*) view;
CGFloat borderWidth = rctView.borderWidth;
if (borderWidth > 0.0f) {
bounds.origin.x += borderWidth;
bounds.origin.y += borderWidth;
bounds.size.width -= (borderWidth * 2.0f);
bounds.size.height -= (borderWidth * 2.0f);
}
}
if (CGRectEqualToRect(subview.frame, bounds)) {
//NSLog(@"RESOLVED IMAGE VIEW, frame: %@, bounds: %@", NSStringFromCGRect(subview.frame), NSStringFromCGRect(bounds));
return [RNSharedElementNodeResolvedSource sourceWithView:view hasChildImageView:YES];
}
}
}
Expand All @@ -110,16 +162,27 @@ + (UIView*) resolveView:(UIView*) view
}
}
}
if (foundImageView != nil) return foundImageView;
if (foundImageView != nil) {
return [RNSharedElementNodeResolvedSource sourceWithView:foundImageView];
}
}
return view;
return [RNSharedElementNodeResolvedSource sourceWithView:view];
}

- (void) addContentObservers:(UIView*)view
- (void) addStyleObservers:(UIView*)view
{
[view addObserver:self forKeyPath:@"bounds" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

}

- (void) removeStyleObservers:(UIView*)view
{
[view removeObserver:self forKeyPath:@"bounds"];
[view removeObserver:self forKeyPath:@"frame"];
}

- (void) addContentObservers:(UIView*)view
{
if ([RNSharedElementContent isKindOfImageView:view]) {
UIImageView* imageView = [RNSharedElementContent imageViewFromView:view];
[imageView addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
Expand All @@ -128,9 +191,6 @@ - (void) addContentObservers:(UIView*)view

- (void) removeContentObservers:(UIView*)view
{
[view removeObserver:self forKeyPath:@"bounds"];
[view removeObserver:self forKeyPath:@"frame"];

if ([RNSharedElementContent isKindOfImageView:view]) {
UIImageView* imageView = [RNSharedElementContent imageViewFromView:view];
[imageView removeObserver:self forKeyPath:@"image"];
Expand All @@ -140,9 +200,11 @@ - (void) removeContentObservers:(UIView*)view
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//NSLog(@"observeValueForKeyPath: %@, changed: %@", keyPath, change);
self.view = [RNSharedElementNode resolveView:_isParent ? _sourceView.subviews.firstObject : _sourceView];
[self updateStyle];
[self updateContent];
if ([keyPath isEqualToString:@"image"]) {
[self updateContent];
} else {
[self updateStyle];
}
}

- (void) setRefCount:(long)refCount {
Expand All @@ -152,9 +214,9 @@ - (void) setRefCount:(long)refCount {
[_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
_displayLink = nil;
}
self.view = nil;
[self updateResolvedSource:NO];
if (_isParent && (_sourceView != nil)) {
[self removeContentObservers:_sourceView];
[self removeStyleObservers:_sourceView];
}
}
}
Expand All @@ -167,10 +229,10 @@ - (void) setHideRefCount:(long)refCount
{
_hideRefCount = refCount;
if (_hideRefCount == 1) {
if (_view != nil) _view.hidden = YES;
if (_resolvedSource.view != nil) _resolvedSource.view.hidden = YES;
}
else if (_hideRefCount == 0) {
if (_view != nil) _view.hidden = NO;
if (_resolvedSource.view != nil) _resolvedSource.view.hidden = NO;
}
}

Expand All @@ -194,7 +256,11 @@ - (void) requestContent:(__weak id <RNSharedElementDelegate>) delegate

- (void) updateContent
{
UIView* view = self.view;
// Update the resolved source
[self updateResolvedSource:YES];
RNSharedElementNodeResolvedSource* resolvedSource = _resolvedSource;
UIView* view = resolvedSource.view;
UIView* contentView = resolvedSource.contentView;
if (view == nil) return;
if (_contentRequests == nil) return;

Expand All @@ -207,8 +273,8 @@ - (void) updateContent
NSObject* content;
RNSharedElementContentType contentType;

if ([RNSharedElementContent isKindOfImageView:view]) {
UIImageView* imageView = [RNSharedElementContent imageViewFromView:view];
if ([RNSharedElementContent isKindOfImageView:contentView]) {
UIImageView* imageView = [RNSharedElementContent imageViewFromView:contentView];
UIImage* image = imageView.image;
content = image;
contentType = RNSharedElementContentTypeRawImage;
Expand All @@ -218,20 +284,20 @@ - (void) updateContent
contentType = RNSharedElementContentTypeSnapshotView;
}
else {
UIView* snapshotView = [_view snapshotViewAfterScreenUpdates:NO];
UIView* snapshotView = [view snapshotViewAfterScreenUpdates:NO];
content = snapshotView;
contentType = RNSharedElementContentTypeSnapshotView;
}
/*else {
NSLog(@"drawViewHierarchyInRect: bounds: %@", NSStringFromCGRect(bounds));
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0.0f);
BOOL res = [view drawViewHierarchyInRect:bounds afterScreenUpdates:NO]; // NEVER USE YES, IT CREATED VISUAL ARTEFACTS ON THE CREEN
UIImage* image = res ? UIGraphicsGetImageFromCurrentImageContext() : nil;
UIGraphicsEndImageContext();
NSLog(@"drawViewHierarchyInRect: RESULT: %li", res);
content = image;
contentType = RNSharedElementContentTypeSnapshotImage;
}*/
NSLog(@"drawViewHierarchyInRect: bounds: %@", NSStringFromCGRect(bounds));
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0.0f);
BOOL res = [view drawViewHierarchyInRect:bounds afterScreenUpdates:NO]; // NEVER USE YES, IT CREATED VISUAL ARTEFACTS ON THE CREEN
UIImage* image = res ? UIGraphicsGetImageFromCurrentImageContext() : nil;
UIGraphicsEndImageContext();
NSLog(@"drawViewHierarchyInRect: RESULT: %li", res);
content = image;
contentType = RNSharedElementContentTypeSnapshotImage;
}*/

// If the content could not be obtained, then try again later
if (content == nil) {
Expand Down Expand Up @@ -280,7 +346,10 @@ - (void) requestStyle:(__weak id <RNSharedElementDelegate>) delegate

- (void) updateStyle
{
UIView* view = self.view;
[self updateResolvedSource:YES];
RNSharedElementNodeResolvedSource* resolvedSource = _resolvedSource;
UIView* view = resolvedSource.view;
UIView* contentView = resolvedSource.contentView;
if (_styleRequests == nil) return;
if (view == nil) return;

Expand All @@ -291,13 +360,15 @@ - (void) updateStyle
// Create style
RNSharedElementStyle* style = [[RNSharedElementStyle alloc]initWithView:view];
style.layout = layout;
if ([RNSharedElementContent isKindOfImageView:view]) {
UIImageView* imageView = [RNSharedElementContent imageViewFromView:view];
if ([RNSharedElementContent isKindOfImageView:contentView]) {
UIImageView* imageView = [RNSharedElementContent imageViewFromView:contentView];
style.contentMode = imageView.contentMode;
} else {
style.contentMode = view.contentMode;
}
// NSLog(@"Style fetched: %@, realSize: %@, opacity: %lf, transform: %@, borderWidth: %lf", NSStringFromCGRect(layout), NSStringFromCGSize(style.size), style.opacity, [RNSharedElementStyle stringFromTransform:style.transform], style.borderWidth);
/*if (_isParent) {
NSLog(@"Style fetched: %@, realSize: %@, opacity: %lf, transform: %@, borderWidth: %lf, contentMode: %ld", NSStringFromCGRect(layout), NSStringFromCGSize(style.size), style.opacity, [RNSharedElementStyle stringFromTransform:style.transform], style.borderWidth, style.contentMode);
}*/

_styleCache = style;

Expand Down

0 comments on commit 8571cc5

Please sign in to comment.