Skip to content

Instantly share code, notes, and snippets.

@RaneWallin
Last active June 28, 2017 19:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RaneWallin/d8addddcaa460f23d91206d4d3625d50 to your computer and use it in GitHub Desktop.
Save RaneWallin/d8addddcaa460f23d91206d4d3625d50 to your computer and use it in GitHub Desktop.
A React Native component that allows the user to control the scrolling content by tapping up and down icons.
/**
* Created by rane on 6/28/17.
* TapControlledScrollView
* This component allows the user to scroll through content using
* up and down icons. The default scroll behavior is disabled.
*
* scrollDistance property determines how far the view scrolls. Default is 30
*
* Usage:
* <TapControlledScrollView
* scrollDistance="30"
* >
* ...
* </TapControlledScrollView>
*/
import React, { Component } from 'react';
import {
ScrollView,
View,
TouchableOpacity,
} from 'react-native';
import NativeMethodsMixin from 'NativeMethodsMixin';
import Icon from 'react-native-vector-icons/EvilIcons';
class TapControlledScrollView extends Component {
// this.state.scrollPosition is the current y position of the scroll view contents
state = ({
scrollPosition: 0,
topVisible: false,
bottomVisible: false
});
doScroll = (direction, distance) => {
let way = (direction && direction === 'up') ? -1 : 1;
return { x: 0, y: this.state.scrollPosition + distance * way, animated: true }
}
doIconPress = (direction, distance) => {
this.refs['_ScrollView'].scrollTo(this.doScroll(direction, distance));
}
watchScroll = (event) => {
const nEvent = event.nativeEvent;
this.setState({
scrollPosition: nEvent.contentOffset.y
});
if ((nEvent.contentOffset.y +
nEvent.layoutMeasurement.height) >=
nEvent.contentSize.height) {
this.setState({ bottomVisible: false });
} else {
this.setState({ bottomVisible: true });
}
}
renderIcon(which) {
switch(which) {
case 'top':
if (this.state.scrollPosition > 0) {
return (
<Icon
style={ [styles.iconStyle] }
name="chevron-up"
/>
)
}
break;
case 'bottom':
if(this.state.bottomVisible) {
return (
<Icon
style={ styles.iconStyle }
name="chevron-down"
/>
);
}
break;
}
}
setIcons(contentHeight) {
NativeMethodsMixin.measure.call(this.refs['_ScrollView'],
(x, y, width, height) => {
if(contentHeight > height) {
this.setState({ bottomVisible: true })
} else {
this.setState({ bottomVisible: false });
}
}
)
}
render() {
if(!this.props.scrollDistance)this.props.scrollDistance=30;
return(
<View style={{ flex: 1, flexDirection: 'row' }}>
<ScrollView
style={{ flex: 1 }}
showsHorizontalScrollIndicator={ false }
showsVerticalScrollIndicator={ false }
onContentSizeChange={ (width, height) => this.setIcons(height) }
//onLayout={ (event) => this.setIcons(event) }
onScroll={ (event) => this.watchScroll(event) }
scrollEnabled={ false }
ref="_ScrollView"
>
{ this.props.children }
</ScrollView>
<View
style={{
flexDirection: 'column',
justifyContent: 'space-between'
}}
>
<TouchableOpacity
style={{ alignSelf: 'flex-start'}}
onPress={ this.doIconPress.bind(this, 'up', this.props.scrollDistance) }
>
{ this.renderIcon('top') }
</TouchableOpacity>
<TouchableOpacity
style={{ alignSelf: 'flex-end' }}
onPress={ this.doIconPress.bind(this, 'down', this.props.scrollDistance) }
>
{ this.renderIcon('bottom') }
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = {
iconStyle: {
fontSize: 50,
textAlign: 'center'
}
}
export default TapControlledScrollView;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment