Skip to content

Instantly share code, notes, and snippets.

@florindumitru
Created October 29, 2020 09:49
Show Gist options
  • Select an option

  • Save florindumitru/6e53799cc1d820f4d0099cd72f5f9666 to your computer and use it in GitHub Desktop.

Select an option

Save florindumitru/6e53799cc1d820f4d0099cd72f5f9666 to your computer and use it in GitHub Desktop.
Swipeable React native Bottom Card
import * as React from 'react';
import {
Text,
View,
StyleSheet,
Animated,
PanResponder,
Easing,
} from 'react-native';
import { Dimensions } from 'react-native';
export default class BottomCard extends React.Component {
constructor(props) {
super(props);
this.windowWidth = Dimensions.get('window').width;
this.windowHeight = Dimensions.get('window').height;
let defaultTop = 150;
if (this.props.topDistance) {
defaultTop = this.props.topDistance;
}
this.modalH = Dimensions.get('window').height - defaultTop;
this.down = 0 - this.modalH + 100;
this.state = {
posY: new Animated.Value(0 - this.modalH + 100),
};
this.panResponder = PanResponder.create({
//Step 2
onStartShouldSetPanResponder: () => true,
onPanResponderRelease: (e, gesture) => {
if (gesture.dy > 0) {
Animated.timing(this.state.posY, {
toValue: this.down,
duration: 150,
easing: Easing.linear,
}).start();
} else {
Animated.timing(this.state.posY, {
toValue: 0,
duration: 150,
easing: Easing.linear,
}).start();
}
}, //Step 4
});
}
open = () => {
Animated.timing(this.state.posY, {
toValue: 0,
duration: 5000,
}).start();
};
render() {
const childrenWithProps = React.Children.map(
this.props.children,
(child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, this.props);
}
return child;
}
);
return (
<Animated.View
{...this.panResponder.panHandlers}
style={{
position: 'absolute',
zIndex: 999,
bottom: this.state.posY,
width: Dimensions.get('window').width,
height: this.modalH,
backgroundColor: this.props.backgroundColor || 'teal',
borderTopLeftRadius: 35,
borderTopRightRadius: 35,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
}}>
<View
style={{
position: 'absolute',
opacity: 0.5,
width: 50,
height: 5,
backgroundColor: 'white',
borderRadius: 10,
alignSelf: 'center',
marginTop: 10,
}}></View>
{childrenWithProps}
</Animated.View>
);
}
}
@florindumitru
Copy link
Author

florindumitru commented Oct 29, 2020

Usage:

import { Text, View, StyleSheet, TextInput } from 'react-native';
import BottomCard from './BottomCard';

export default class App extends React.Component {
  render() {
    return(
      <View style={styles.container}>
      <Text style={{fontSize: 40, marginTop: 40, marginLeft: 20, fontWeight: "bold"}}>My App</Text>
      <BottomCard topDistance={150} backgroundColor= "green">
        <Text style={{alignSelf: "center", marginTop: 35, color: "white", fontWeight: "bold", fontSize: 20}}>Add new task</Text>
      </BottomCard>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#ecf0f1',
  },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment