Created
April 21, 2017 08:10
-
-
Save kmagiera/710460dac3ba722bb6a8d552c343b44a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react' | |
import { View, Image, StyleSheet, ScrollView, Text, Animated, StatusBar, PixelRatio } from 'react-native' | |
import Icon from 'react-native-vector-icons/MaterialIcons'; | |
import MapView from 'react-native-maps'; | |
const AMSTERDAM = { | |
latitude: 52.3702, | |
longitude: 4.8952, | |
latitudeDelta: 0.0922, | |
longitudeDelta: 0.0421, | |
} | |
const OFFSET = 450 | |
class Maps extends Component { | |
render() { | |
return ( | |
<View style={{flex: 1}}> | |
<MapView style={{flex: 1}} initialRegion={AMSTERDAM}/> | |
<Drawer /> | |
</View> | |
) | |
} | |
} | |
class Drawer extends Component { | |
constructor(props) { | |
super(props) | |
this.state = { | |
expanded: false, | |
} | |
} | |
handleEndDrag = (e) => { | |
const targetY = e.nativeEvent.targetContentOffset.y | |
if (targetY < OFFSET) { | |
const snap = targetY < OFFSET / 3 ? 0 : OFFSET | |
this.refs["Scroll"].scrollTo({ y: snap }) | |
} | |
} | |
handleBeginDrag = (e) => { | |
this.setState({ expanded: true }) | |
} | |
handleAnimationEnd = (e) => { | |
const scrollY = e.nativeEvent.contentOffset.y | |
this.setState({ expanded: scrollY > 0 }) | |
} | |
render() { | |
return ( | |
<View style={[styles.container, { overflow: this.state.expanded ? 'visible' : 'hidden' }]}> | |
<ScrollView | |
style={styles.full} | |
stickyHeaderIndices={[1]} | |
showsVerticalScrollIndicator={false} | |
contentInset={{bottom: -255}} | |
ref="Scroll" | |
onScrollEndDrag={this.handleEndDrag} | |
onScrollBeginDrag={this.handleBeginDrag} | |
onMomentumScrollEnd={this.handleAnimationEnd} | |
> | |
<View style={styles.placeholder} /> | |
<View style={styles.header}> | |
<View style={styles.handle} /> | |
<Text style={styles.headerText}>Sticky header (pull here)</Text> | |
</View> | |
<Row icon="event-seat" text="Go watch a movie" color="#3949ab"/> | |
<Row icon="euro-symbol" text="Find some ca$$h" color="#00695c"/> | |
<Row icon="rowing" text="Random guy with a paddle" color="#827717"/> | |
<Row icon="radio" text="Very old radio" color="#6d4c41"/> | |
<Row icon="airplanemode-active" text="Fly away" color="#424242"/> | |
<Row icon="usb" text="Buy some USBs" color="#546e7a"/> | |
<Row icon="explore" text="Maybe use internet explorer" color="#e53935"/> | |
<Row icon="watch" text="Charge your watch..." color="#ff8f00"/> | |
<Row icon="wb-sunny" text="Good weather!" color="#1b5e20"/> | |
<Row icon="local-hospital" text="Need help?" color="#ad1457"/> | |
<Row icon="restaurant" text="Some fancy restaurant" color="#6a1b9a"/> | |
<Row icon="directions-bike" text="Get on a bike" color="#c0ca33"/> | |
<View style={styles.white}/> | |
</ScrollView> | |
</View> | |
) | |
} | |
} | |
const Row = ({icon, text, color}) => ( | |
<View style={styles.row}> | |
<View style={[styles.rowIconContainer, {backgroundColor: color}]}> | |
<Icon name={icon} size={20} color="white" /> | |
</View> | |
<Text style={styles.rowText}>{text}</Text> | |
</View> | |
) | |
const styles = StyleSheet.create({ | |
container: { | |
position: 'absolute', | |
left: 0, | |
right: 0, | |
top: 40 + OFFSET, | |
bottom: 0, | |
}, | |
full: { | |
marginTop: -OFFSET, | |
flex: 1, | |
}, | |
header: { | |
backgroundColor: 'white', | |
height: 62, | |
borderTopWidth: 1 / PixelRatio.get(), | |
borderBottomWidth: 1 / PixelRatio.get(), | |
borderColor: '#8C99A5', | |
alignItems: 'center', | |
}, | |
handle: { | |
width: 40, | |
height: 8, | |
borderRadius: 4, | |
backgroundColor: '#8C99A5', | |
margin: 4, | |
}, | |
placeholder: { | |
height: OFFSET, | |
}, | |
headerText: { | |
flex: 1, | |
fontSize: 22, | |
}, | |
row: { | |
height: 60, | |
flex: 1, | |
flexDirection: 'row', | |
alignItems: 'center', | |
backgroundColor: 'white', | |
borderBottomWidth: 1 / PixelRatio.get(), | |
borderColor: '#8C99A5', | |
}, | |
rowIconContainer: { | |
margin: 10, | |
width: 30, | |
height: 30, | |
borderRadius: 15, | |
alignItems: 'center', | |
justifyContent: 'center', | |
overflow: 'hidden', | |
}, | |
rowText: { | |
fontSize: 18, | |
}, | |
white: { | |
height: 255, | |
backgroundColor: 'white', | |
}, | |
}) | |
export default Maps |
@ferrannp is this on iOS or android? I think the targetContentOffset may not be available on android in which case you may need to find another workaround.
As for the content behind being clickable this example should provide that. It works by changing the container size in which the scollview is placed (this.state.expanded
is responsible for that)
Sorry for late response one again
@kmagiera yup Android, also the content behind is clickable on iOS but not on Android... So it looks like that getting this on Android https://material.io/guidelines/components/bottom-sheets.html#bottom-sheets-usage it is very tricky...
Hey @kmagiera - running into a similar issue with Android as above. Any pointers would be much appreciated!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey @kmagiera! First of all, great talk at React Amsterdam and thanks for this snippet! I am trying to implement the Material Bottom Sheets with this example. I need to figure out a couple of things: Content behind to be clickable + add and overlay that changes opacity while the sheet is moving.
I am writing this because I tested the snippet and every time I end dragging, I receive an exception:
I didn't really check why is this happening but a preventive check seems to work:
I use
react-native: 0.43.4
andreact: 16.0.0-alpha.6
.