[IMPROVEMENT] Use Reanimated's Transitions instead of LayoutAnimation (#1206)
* [IMPROVEMENT] Use Reanimated's Transitions instead of LayoutAnimation * Don't run on Android * Refactor * Remove unnecessary code
This commit is contained in:
parent
b29a2ab216
commit
81198b4c4f
|
@ -1,77 +0,0 @@
|
|||
import { View, Animated } from 'react-native';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
export default class Panel extends React.Component {
|
||||
static propTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
style: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
animation: new Animated.Value()
|
||||
};
|
||||
this.first = true;
|
||||
this.open = false;
|
||||
this.opacity = 0;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { animation } = this.state;
|
||||
const { open } = this.props;
|
||||
const initialValue = !open ? this.height : 0;
|
||||
animation.setValue(initialValue);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { animation } = this.state;
|
||||
const { open } = this.props;
|
||||
|
||||
if (this.first) {
|
||||
this.first = false;
|
||||
if (!open) {
|
||||
animation.setValue(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.open === nextProps.open) {
|
||||
return;
|
||||
}
|
||||
this.open = nextProps.open;
|
||||
const initialValue = !nextProps.open ? this.height : 0;
|
||||
const finalValue = !nextProps.open ? 0 : this.height;
|
||||
|
||||
animation.setValue(initialValue);
|
||||
Animated.timing(
|
||||
animation,
|
||||
{
|
||||
toValue: finalValue,
|
||||
duration: 150,
|
||||
useNativeDriver: true
|
||||
}
|
||||
).start();
|
||||
}
|
||||
|
||||
set _height(h) {
|
||||
this.height = h || this.height;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { animation } = this.state;
|
||||
const { style, children } = this.props;
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[{ height: animation }, style]}
|
||||
>
|
||||
<View onLayout={({ nativeEvent }) => this._height = nativeEvent.layout.height} style={{ position: !this.first ? 'relative' : 'absolute' }}>
|
||||
{children}
|
||||
</View>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { Animated, Text } from 'react-native';
|
||||
|
||||
export default class Fade extends React.Component {
|
||||
static propTypes = {
|
||||
visible: PropTypes.bool.isRequired,
|
||||
style: Animated.View.propTypes.style,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node
|
||||
])
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { visible } = this.props;
|
||||
this.state = {
|
||||
visible
|
||||
};
|
||||
this._visibility = new Animated.Value(visible ? 1 : 0);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.visible) {
|
||||
this.setState({ visible: true });
|
||||
}
|
||||
Animated.timing(this._visibility, {
|
||||
toValue: nextProps.visible ? 1 : 0,
|
||||
duration: 300,
|
||||
useNativeDriver: true
|
||||
}).start(() => {
|
||||
this.setState({ visible: nextProps.visible });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { visible } = this.state;
|
||||
const { style, children, ...rest } = this.props;
|
||||
|
||||
const containerStyle = {
|
||||
opacity: this._visibility.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, 1]
|
||||
}),
|
||||
transform: [
|
||||
{
|
||||
scale: this._visibility.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1.1, 1]
|
||||
})
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const combinedStyle = [containerStyle, style];
|
||||
return (
|
||||
<Animated.View style={visible ? combinedStyle : containerStyle} {...rest}>
|
||||
<Text>{visible ? children : null}</Text>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
}
|
15
app/index.js
15
app/index.js
|
@ -19,6 +19,7 @@ import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
|||
import { loggerConfig, analytics } from './utils/log';
|
||||
import Toast from './containers/Toast';
|
||||
import RocketChat from './lib/rocketchat';
|
||||
import LayoutAnimation from './utils/layoutAnimation';
|
||||
|
||||
useScreens();
|
||||
|
||||
|
@ -308,12 +309,14 @@ export default class Root extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<App
|
||||
ref={(navigatorRef) => {
|
||||
Navigation.setTopLevelNavigator(navigatorRef);
|
||||
}}
|
||||
onNavigationStateChange={onNavigationStateChange}
|
||||
/>
|
||||
<LayoutAnimation>
|
||||
<App
|
||||
ref={(navigatorRef) => {
|
||||
Navigation.setTopLevelNavigator(navigatorRef);
|
||||
}}
|
||||
onNavigationStateChange={onNavigationStateChange}
|
||||
/>
|
||||
</LayoutAnimation>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
|
15
app/share.js
15
app/share.js
|
@ -11,6 +11,7 @@ import sharedStyles from './views/Styles';
|
|||
import { isNotch, isIOS } from './utils/deviceInfo';
|
||||
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
|
||||
import RocketChat from './lib/rocketchat';
|
||||
import LayoutAnimation from './utils/layoutAnimation';
|
||||
|
||||
const InsideNavigator = createStackNavigator({
|
||||
ShareListView: {
|
||||
|
@ -84,12 +85,14 @@ class Root extends React.Component {
|
|||
onLayout={this.handleLayout}
|
||||
>
|
||||
<Provider store={store}>
|
||||
<AppContainer
|
||||
ref={(navigatorRef) => {
|
||||
Navigation.setTopLevelNavigator(navigatorRef);
|
||||
}}
|
||||
onNavigationStateChange={onNavigationStateChange}
|
||||
/>
|
||||
<LayoutAnimation>
|
||||
<AppContainer
|
||||
ref={(navigatorRef) => {
|
||||
Navigation.setTopLevelNavigator(navigatorRef);
|
||||
}}
|
||||
onNavigationStateChange={onNavigationStateChange}
|
||||
/>
|
||||
</LayoutAnimation>
|
||||
</Provider>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react';
|
||||
import { Transition, Transitioning } from 'react-native-reanimated';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import debounce from './debounce';
|
||||
import { isIOS } from './deviceInfo';
|
||||
import sharedStyles from '../views/Styles';
|
||||
|
||||
const transition = (
|
||||
<Transition.Together>
|
||||
<Transition.In type='fade' />
|
||||
<Transition.Out type='fade' />
|
||||
<Transition.Change interpolation='easeInOut' />
|
||||
</Transition.Together>
|
||||
);
|
||||
|
||||
const TRANSITION_REF = React.createRef();
|
||||
|
||||
export const animateNextTransition = debounce(() => {
|
||||
if (isIOS) {
|
||||
TRANSITION_REF.current.animateNextTransition();
|
||||
}
|
||||
}, 200, true);
|
||||
|
||||
const LayoutAnimation = ({ children }) => {
|
||||
if (isIOS) {
|
||||
return (
|
||||
<Transitioning.View
|
||||
style={sharedStyles.root}
|
||||
transition={transition}
|
||||
ref={TRANSITION_REF}
|
||||
>
|
||||
{children}
|
||||
</Transitioning.View>
|
||||
);
|
||||
}
|
||||
return children;
|
||||
};
|
||||
|
||||
LayoutAnimation.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default LayoutAnimation;
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Keyboard, Text, ScrollView, View, StyleSheet, Alert, LayoutAnimation
|
||||
Keyboard, Text, ScrollView, View, StyleSheet, Alert
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
@ -18,6 +18,7 @@ import { loginRequest as loginRequestAction } from '../actions/login';
|
|||
import { LegalButton } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { COLOR_PRIMARY } from '../constants/colors';
|
||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
bottomContainer: {
|
||||
|
@ -84,7 +85,7 @@ class LoginView extends React.Component {
|
|||
this.setTitle(nextProps.Site_Name);
|
||||
} else if (nextProps.failure && !equal(error, nextProps.error)) {
|
||||
if (nextProps.error && nextProps.error.error === 'totp-required') {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
this.setState({ showTOTP: true });
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Text, ScrollView, Keyboard, Image, StyleSheet, TouchableOpacity, View, Alert, LayoutAnimation
|
||||
Text, ScrollView, Keyboard, Image, StyleSheet, TouchableOpacity, View, Alert
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
@ -23,6 +23,7 @@ import { CustomIcon } from '../lib/Icons';
|
|||
import StatusBar from '../containers/StatusBar';
|
||||
import { COLOR_PRIMARY } from '../constants/colors';
|
||||
import log from '../utils/log';
|
||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
|
@ -195,7 +196,7 @@ class NewServerView extends React.Component {
|
|||
uriToPath = uri => uri.replace('file://', '');
|
||||
|
||||
saveCertificate = (certificate) => {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
this.setState({ certificate });
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
ActivityIndicator, FlatList, InteractionManager, LayoutAnimation
|
||||
ActivityIndicator, FlatList, InteractionManager
|
||||
} from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
@ -15,6 +15,7 @@ import RocketChat from '../../lib/rocketchat';
|
|||
import log from '../../utils/log';
|
||||
import EmptyRoom from './EmptyRoom';
|
||||
import { isIOS } from '../../utils/deviceInfo';
|
||||
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||
|
||||
export class List extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -83,7 +84,7 @@ export class List extends React.Component {
|
|||
}
|
||||
const messages = orderBy(data, ['ts'], ['desc']);
|
||||
if (this.mounted) {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
this.setState({ messages });
|
||||
} else {
|
||||
this.state.messages = messages;
|
||||
|
@ -186,11 +187,11 @@ export class List extends React.Component {
|
|||
style={styles.list}
|
||||
inverted
|
||||
removeClippedSubviews={isIOS}
|
||||
initialNumToRender={7}
|
||||
// initialNumToRender={7}
|
||||
onEndReached={this.onEndReached}
|
||||
onEndReachedThreshold={5}
|
||||
maxToRenderPerBatch={5}
|
||||
windowSize={10}
|
||||
// onEndReachedThreshold={5}
|
||||
// maxToRenderPerBatch={5}
|
||||
// windowSize={10}
|
||||
ListFooterComponent={this.renderFooter}
|
||||
{...scrollPersistTaps}
|
||||
/>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Text, View, InteractionManager, LayoutAnimation
|
||||
} from 'react-native';
|
||||
import { Text, View, InteractionManager } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
|
@ -484,15 +482,11 @@ class RoomView extends React.Component {
|
|||
if (!this.mounted) {
|
||||
return;
|
||||
}
|
||||
if (isIOS && this.beginAnimating) {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
}
|
||||
this.setState(...args);
|
||||
}
|
||||
|
||||
sendMessage = (message, tmid) => {
|
||||
const { user } = this.props;
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
RocketChat.sendMessage(this.rid, message, this.tmid || tmid, user).then(() => {
|
||||
this.setLastOpen(null);
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
Text,
|
||||
ScrollView,
|
||||
Keyboard,
|
||||
LayoutAnimation,
|
||||
Dimensions
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
@ -43,6 +42,7 @@ import {
|
|||
import StatusBar from '../../containers/StatusBar';
|
||||
import ListHeader from './ListHeader';
|
||||
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
|
||||
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||
|
||||
const SCROLL_OFFSET = 56;
|
||||
|
||||
|
@ -290,8 +290,8 @@ class RoomsListView extends React.Component {
|
|||
// eslint-disable-next-line react/sort-comp
|
||||
internalSetState = (...args) => {
|
||||
const { navigation } = this.props;
|
||||
if (isIOS && navigation.isFocused()) {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
if (navigation.isFocused()) {
|
||||
animateNextTransition();
|
||||
}
|
||||
this.setState(...args);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, StyleSheet, FlatList, LayoutAnimation
|
||||
} from 'react-native';
|
||||
import { View, StyleSheet, FlatList } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import equal from 'deep-equal';
|
||||
|
@ -25,6 +23,7 @@ import sharedStyles from './Styles';
|
|||
import { Item, CustomHeaderButtons } from '../containers/HeaderButton';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { COLOR_WHITE } from '../constants/colors';
|
||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeAreaView: {
|
||||
|
@ -169,7 +168,7 @@ class SelectedUsersView extends React.Component {
|
|||
toggleUser = (user) => {
|
||||
const { addUser, removeUser } = this.props;
|
||||
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
if (!this.isChecked(user.name)) {
|
||||
addUser(user);
|
||||
} else {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Keyboard, LayoutAnimation, View, StyleSheet
|
||||
} from 'react-native';
|
||||
import { Keyboard, View, StyleSheet } from 'react-native';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
|
||||
import SearchBox from '../../../containers/SearchBox';
|
||||
|
@ -10,6 +8,7 @@ import { CloseShareExtensionButton } from '../../../containers/HeaderButton';
|
|||
import { HEADER_BACKGROUND } from '../../../constants/colors';
|
||||
|
||||
import sharedStyles from '../../Styles';
|
||||
import { animateNextTransition } from '../../../utils/layoutAnimation';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -33,12 +32,12 @@ const Header = React.memo(({
|
|||
Keyboard.dismiss();
|
||||
onChangeText('');
|
||||
cancelSearch();
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
};
|
||||
|
||||
const onFocus = () => {
|
||||
initSearch();
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, Text, LayoutAnimation, FlatList, ActivityIndicator, Keyboard, BackHandler
|
||||
View, Text, FlatList, ActivityIndicator, Keyboard, BackHandler
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
|
@ -25,6 +25,7 @@ import ShareListHeader from './Header';
|
|||
|
||||
import styles from './styles';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||
|
||||
const LIMIT = 50;
|
||||
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
|
||||
|
@ -174,8 +175,8 @@ class ShareListView extends React.Component {
|
|||
// eslint-disable-next-line react/sort-comp
|
||||
internalSetState = (...args) => {
|
||||
const { navigation } = this.props;
|
||||
if (isIOS && navigation.isFocused()) {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
if (navigation.isFocused()) {
|
||||
animateNextTransition();
|
||||
}
|
||||
this.setState(...args);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ScrollView, Text, View, FlatList, LayoutAnimation, SafeAreaView
|
||||
ScrollView, Text, View, FlatList, SafeAreaView
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import equal from 'deep-equal';
|
||||
|
@ -20,6 +20,7 @@ import styles from './styles';
|
|||
import SidebarItem from './SidebarItem';
|
||||
import { COLOR_TEXT } from '../../constants/colors';
|
||||
import database from '../../lib/database';
|
||||
import { animateNextTransition } from '../../utils/layoutAnimation';
|
||||
|
||||
const keyExtractor = item => item.id;
|
||||
|
||||
|
@ -147,7 +148,7 @@ class Sidebar extends Component {
|
|||
}
|
||||
|
||||
toggleStatus = () => {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
animateNextTransition();
|
||||
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ import {
|
|||
} from '../constants/colors';
|
||||
|
||||
export default StyleSheet.create({
|
||||
root: {
|
||||
flex: 1
|
||||
},
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
flex: 1
|
||||
|
|
Loading…
Reference in New Issue