Evil Bridges and Blocked Threads
Cross Platform
Web Technology (Javascript)
ReactJS like
Javascript Runtime
Layouting Overhead
Data Serialization
Bridge
declarative programming focuses on what the program should accomplish.
Benefits:
Easy to Optimize
Imperative programming focuses on describing how a program operates.
Benefits:
Easy to describe complex operations.
import { Animated } from 'react-native';import React from "react";
import { Animated, TouchableOpacity, Text } from "react-native";
export default class AnimatedBox extends React.Component {
animatedValue = new Animated.Value(0);
handlePress = () => {
Animated.spring(this.animatedValue, {
toValue: 100,
tension: 30,
friction: 12,
useNativeDriver: true
}).start();
};
render() {
const style = {
height: 100,
width: 100,
backgroundColor: "red"
};
const animatedStyle = {
transform: [{ translateX: this.animatedValue }]
};
return (
<Animated.View style={animatedStyle}>
<TouchableOpacity style={style} onPress={this.handlePress}>
<Text>Press here</Text>
</TouchableOpacity>
</Animated.View>
);
}
}
import React from "react";
import { Animated, View, PanResponder } from "react-native";
export default class AnimatedBox extends React.Component {
translateX = new Animated.Value(1);
translateXValue = 0;
translateY = new Animated.Value(1);
translateYValue = 0;
responder = PanResponder.create({
...
});
componentDidMount() {
this.translateY.addListener(({ value }) => {
this.translateYValue = value;
});
this.translateX.addListener(({ value }) => {
this.translateXValue = value;
});
}
render() {
const style = {
...
};
return <Animated.View style={style} {...this.responder.panHandlers} />;
}
}
export default class AnimatedBox extends React.Component {
translateX = new Animated.Value(1);
translateXValue = 0;
translateY = new Animated.Value(1);
translateYValue = 0;
responder = PanResponder.create({
onMoveShouldSetPanResponder: (e, gestureState) => true,
onPanResponderGrant: () => {
this.translateY.setOffset(this.translateYValue);
this.translateY.setValue(0);
this.translateX.setOffset(this.translateXValue);
this.translateX.setValue(0);
},
onPanResponderMove: (e, gestureState) => {
this.translateY.setValue(gestureState.dy);
this.translateX.setValue(gestureState.dx);
},
onPanResponderRelease: (e, gestureState) => {
this.translateY.flattenOffset();
this.translateX.flattenOffset();
}
});
componentDidMount() {
this.translateY.addListener(({ value }) => {
this.translateYValue = value;
});
this.translateX.addListener(({ value }) => {
this.translateXValue = value;
});
}
...
}Not really, PanResponder is written in JS
Do not cross the evil bridge unless necessary!
import {
Animated
} from "react-native";
import { PanGestureHandler, State } from "react-native-gesture-handler";
export class Swipeable extends Component {
// ...
_onHandlerStateChange = ({ nativeEvent }) => {
if (nativeEvent.oldState === State.ACTIVE) {
// ...
}
};
render() {
// ...
return (
<View style={[styles.root, style]} onLayout={this.handleLayout}>
<PanGestureHandler
ref={this.swipeable}
shouldCancelWhenOutside={false}
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onHandlerStateChange}
>
{/* ... */}
</PanGestureHandler>
</View>
);
}
}import { Animated, PanResponder } from "react-native";
export class Swipeable extends Component {
// ...
panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
const dx = Math.abs(gestureState.dx);
const dy = Math.abs(gestureState.dy);
return dx > dy && dx > X_AXIS_CAPTURE_THRESHOLD;
},
onMoveShouldSetPanResponder: () => false,
onPanResponderTerminationRequest: () => false,
onPanResponderRelease: this.handleTouchEnd,
onPanResponderTerminate: this.handleTouchEnd,
onPanResponderMove: this.handleTouchMove,
onPanResponderGrant: this.handleTouchStart
});
handleTouchStart = (event, gestureState) => { ... };
handleTouchMove = (event, gestureState) => { ... };
handleTouchEnd = (event, gestureState) => { ... };
render() {
// ...
return (
<View style={[styles.root, style]} onLayout={this.handleLayout}>
<Animated.View
{...this.panResponder.panHandlers}
style={[styles.container, containerStyle, sceneContainerStyle]}
>
{/* ... */}
</Animated.View>
</View>
);
}
}
Original Swipeable
New Swipeable
render() {
return (
<PanGestureHandler
activeOffsetY={-20}
onGestureEvent={this.handelScaleGesture}
>
<PanGestureHandler
activeOffsetY={20}
onGestureEvent={this.handelTranslateGesture}
>
<View style={{
height: 150,
justifyContent: 'center',
}}>
{/* ... */}
</View>
</PanGestureHandler>
</PanGestureHandler>
);
}return (
<PanGestureHandler
onGestureEvent={event([
{
nativeEvent: ({ translationX: x, translationY: y, state }) => block([
set(this._transX, add(x, offsetX)),
set(this._transY, add(y, offsetY)),
cond(
eq(state, State.END),
[
set(this.offsetX, add(this.offsetX, x)),
set(this.offsetY, add(this.offsetY, y))
]
)
])
},
])}
>
<Animated.View
style={{
transform: [{
translateX: this._transX, translateY: this._transY }]
}
}
/>
</PanGestureHandler>
);Catch me at: THCE@danskebank.dk
Source code: https://github.com/thupi/db-rn-animations