Skip to content

Instantly share code, notes, and snippets.

@rajivnarayana
Created March 14, 2019 09:41
Show Gist options
  • Save rajivnarayana/b792048e045333b0d490a23ac7c19ce9 to your computer and use it in GitHub Desktop.
Save rajivnarayana/b792048e045333b0d490a23ac7c19ce9 to your computer and use it in GitHub Desktop.
A React Native example to show swipeable views along a curve.
import React, { Component } from "react";
import { Dimensions, View, Easing, StyleSheet, Animated, ART, PanResponder } from "react-native";
const { Path, Surface, Shape } = ART;
const { width : WIDTH } = Dimensions.get("window");
const RADIUS = 10;
const HEIGHT_OF_TABBAR = 64;
const arc = height => {
const w = WIDTH - 2 * RADIUS;
const h = height - 2 * RADIUS;
const r = (w ** 2 + 4 * h ** 2) / (8 * h);
return new Path()
.moveTo(RADIUS, height - RADIUS)
.arc(w, 0, r, r);
};
class SwipeTabs extends Component {
renderView(offset, backgroundColor) {
offset = (offset + 1) % 1;
const height = HEIGHT_OF_TABBAR;
const w = WIDTH - 2 * RADIUS;
const h = height - 2 * RADIUS;
const r = (w ** 2 + 4 * h ** 2) / (8 * h);
const angle = Math.PI - 2 * Math.atan( w / 2 / h );
const currentAngle = angle - 2 * angle * offset;
const cX = WIDTH/ 2 - r * Math.sin(currentAngle);
const cY = RADIUS + r - r * Math.cos(currentAngle);
const left = cX - RADIUS;
const top = cY - RADIUS;
return <View style={[styles.bottu, {left, top, backgroundColor}]}></View>
}
render() {
const height = HEIGHT_OF_TABBAR;
return (<View style={styles.animated}>
<Surface height = {height} width ="100%">
<Shape d={arc(height)} strokeWidth={1} stroke="white" />
</Surface>
{this.renderView(this.props.offset - 0.3333, "cyan")}
{this.renderView(this.props.offset, "red")}
{this.renderView(this.props.offset + 0.3333, "orange")}
</View>)
}
}
export default class CurveMotion extends Component {
state = {
}
componentWillMount() {
this._animatedValue = new Animated.Value(0);
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (event, gestureState) => true,
onMoveShouldSetPanResponder: (event, gestureState) => true,
onPanResponderGrant: (event, gestureState) => {
/* this.setState({backgroundColor : 'red'}); */
// this._animatedValue.setOffset({x : })
},
onPanResponderMove: Animated.event([
null,
{dx: this._animatedValue}
]),
onPanResponderRelease: () => {
// this._animatedValue.extractOffset();
Animated.timing(this._animatedValue, {
toValue : 0,
easing : Easing.in
}).start();
},
});
}
componentDidMount() {
// Animated.timing(this.state.offset, {
// toValue: 0.5,
// duration : 300,
// easing: Easing.in
// }).start();
}
render() {
const clampedAnimatedValue = this._animatedValue.interpolate({
inputRange : [0, WIDTH],
outputRange : [0.5, 0.5 + 1/3],
});
console.log("clampedAnimatedValue",clampedAnimatedValue)
return (
<View style={[styles.container]}>
<View {...this._panResponder.panHandlers} style={[styles.animated]}>
<AnimatedComponent offset={clampedAnimatedValue}></AnimatedComponent>
</View>
</View>
)
}
}
const AnimatedComponent = Animated.createAnimatedComponent(SwipeTabs);
const styles = StyleSheet.create({
container: {
flex : 1,
justifyContent: 'flex-end'
},
animated: {
height : HEIGHT_OF_TABBAR,
backgroundColor: 'green'
},
bottu : {
position: 'absolute',
left : 0,
top: 0,
width : 2 * RADIUS,
height : 2 * RADIUS,
borderRadius : RADIUS,
backgroundColor : 'red'
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment