facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.04k stars 24.32k forks source link

onLayout is not triggered when Animated.event applied on iOS #24219

Closed osdnk closed 4 years ago

osdnk commented 5 years ago

🐛 Bug Report

image

Behavior on Adnroid is expected one.

To Reproduce

Apply valued to transform and bind with Animated.event set to onLayout prop in Animated.View.

Expected Behavior

iOS should look like Android here. The value should hold a result of Animated.event's invocation.

Code Example

import React from 'react';
import { StyleSheet, View, Animated as NativeAnimated } from 'react-native';

export default class Example extends React.Component {
  constructor(props) {
    super(props);
    this.val2 = new NativeAnimated.Value(0);
  }
  render() {
    return (
      <View style={styles.container}>
        <NativeAnimated.View
          onLayout={NativeAnimated.event([
            {
              nativeEvent: {
                layout: {
                  height: this.val2
                }
              }
            }
          ], {
            useNativeDriver: true
          })}
          style={[
            styles.box,
            {
              backgroundColor: 'green',
              transform: [
                {
                  translateY: this.val2
                }
              ]
            }
          ]}
        />
        <NativeAnimated.View
          style={[
            styles.box,
            {
              backgroundColor: 'blue',
            }
          ]}
        />
      </View>
    );
  }
}

const CIRCLE_SIZE = 70;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',

  },
  box: {
    position: 'absolute',
    backgroundColor: 'tomato',
    marginLeft: -(CIRCLE_SIZE / 2),
    marginTop: -(CIRCLE_SIZE / 2),
    width: CIRCLE_SIZE,
    height: CIRCLE_SIZE,
    borderRadius: CIRCLE_SIZE / 2,
    borderColor: '#000',
  },
});

Environment

  React Native Environment Info:
    System:
      OS: macOS 10.14
      CPU: (8) x64 Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
      Memory: 163.80 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 10.11.0 - ~/.nvm/versions/node/v10.11.0/bin/node
      Yarn: 1.13.0 - ~/.nvm/versions/node/v10.11.0/bin/yarn
      npm: 6.4.1 - ~/.nvm/versions/node/v10.11.0/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
      Android SDK:
        API Levels: 21, 23, 24, 25, 26, 27, 28
        Build Tools: 23.0.1, 23.0.2, 23.0.3, 25.0.0, 25.0.2, 25.0.3, 26.0.1, 26.0.2, 26.0.3, 27.0.1, 27.0.3, 28.0.1, 28.0.2, 28.0.3
        System Images: android-26 | Google Play Intel x86 Atom, android-27 | Intel x86 Atom_64
    IDEs:
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3
      react-native: 0.59.2 => 0.59.2
    npmGlobalPackages:
      react-native-cli: 2.0.1
      react-native-create-library: 4.1.2
      react-native-local-cli: 1.0.0-alpha.5
react-native-bot commented 5 years ago

It looks like you are using an older version of React Native. Please update to the latest release, v0.59 and verify if the issue still exists.

The "Resolution: Old Version" label will be removed automatically once you edit your original post with the results of running `react-native info` on a project using the latest release.
osdnk commented 5 years ago

Updated version

osdnk commented 5 years ago

cc @kelset @janicduplessis @kmagiera

osdnk commented 5 years ago

Also, tried to make onLayout as an event:

@interface RCTOnLayoutEvent : NSObject <RCTEvent>

- (instancetype)initWithReactTag:(NSNumber *)reactTag
                                         content:(NSDictionary *)content;

@end

@implementation RCTOnLayoutEvent
{
  NSDictionary *_content;
}

@synthesize viewTag = _viewTag;
@synthesize coalescingKey = _coalescingKey;

- (instancetype)initWithReactTag:(NSNumber *)reactTag
                         content:(NSDictionary *)content
{
  static uint16_t coalescingKey = 0;
  if ((self = [super init])) {
    _coalescingKey = coalescingKey++;
    _viewTag = reactTag;
    _content = content;
  }
  return self;
}

RCT_NOT_IMPLEMENTED(- (instancetype)init)

- (uint16_t)coalescingKey
{
  return _coalescingKey;
}

- (NSString *)eventName
{
  return @"onLayout";
}

- (BOOL)canCoalesce
{
  return NO;
}

+ (NSString *)moduleDotMethod
{
  return @"RCTEventEmitter.receiveEvent";
}

- (NSArray *)arguments
{
  return @[self.viewTag, @"topLayout", _content];
}

- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent {
  return newEvent;
}

@end
  NSDictionary *content = @{
                                @"layout": @{
                                    @"x": @(frame.origin.x),
                                    @"y": @(frame.origin.y),
                                    @"width": @(frame.size.width),
                                    @"height": @(frame.size.height),
                                    },
                                };
  //  shadowView.onLayout(content);
      RCTOnLayoutEvent *layoutEvent = [[RCTOnLayoutEvent alloc] initWithReactTag:reactTag
                                                                         content:content];

And it worked but events are being attached after mounting so this event is dispatching after filling a map with proper values in Native Animated Module.

janicduplessis commented 5 years ago

Sorry I missed this, events defined with RCT{Direct|Bubbling}EventBlock currently do not work with native animated. I made some PRs to fix it a while back but it ended up not getting merged until recently :(

Event improvement PR (prereq, merged): https://github.com/facebook/react-native/pull/15894 Actual fix (needs rebase): https://github.com/facebook/react-native/pull/15611

It should still work but just needs to be rebased on top of #15894

shuangyu commented 5 years ago

similar issue here(waste my whole day :( ): rn version : 0.59.9

image image

zeh commented 5 years ago

In the meantime, has anyone been able to work around this issue? It seems there's no way to re-read the layout at all, and in my current implementation moving from an Animated.View to a View just breaks the layout entirely (because it depends on some animations).

trickeyd commented 5 years ago

Yeah - same here - this has taken up my whole day now. Thought it was going to be a 5 min bug when i first saw it.

This happened after upgrade from 0.57 - 0.59.10

Annoyingly any fix now will be added to > .6 versions and thats not an option for me right now, so need ti figure out a work around.

yairopro commented 5 years ago

Any news about this issue ? I've got the bug on Android too (see snack here).

stale[bot] commented 4 years ago

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

janicduplessis commented 4 years ago

@yairopro Seems like a bug with react-native-reanimated, I changed your example to use Animated and it seems so work fine on Android.

https://snack.expo.io/@janic/onlayout-=-animated.event(..)-not-working

janicduplessis commented 4 years ago

@osdnk Also works in Expo now so I assume my fix made it to a release, if you want to close this (Looks like I don't have the power to close issues anymore :()

kelset commented 4 years ago

(that's super weird! lmk if you want to close it)

janicduplessis commented 4 years ago

@kelset yes please!