This commit is contained in:
ammarahm-ed
2020-01-11 23:05:39 +05:00
parent ea94048294
commit 9e24f2b40e
2 changed files with 233 additions and 144 deletions

View File

@@ -1,13 +1,16 @@
import React, {useState} from 'react'; import React, {Component} from 'react';
import { import {
View, View,
TouchableOpacity, TouchableOpacity,
Dimensions, Dimensions,
ScrollView, ScrollView,
Modal, Modal,
KeyboardAvoidingView,
Platform,
} from 'react-native'; } from 'react-native';
import PropTypes from 'prop-types';
import {styles} from './styles'; import {styles} from './styles';
let scrollViewRef;
const deviceHeight = Dimensions.get('window').height; const deviceHeight = Dimensions.get('window').height;
const getElevation = elevation => { const getElevation = elevation => {
@@ -20,198 +23,276 @@ const getElevation = elevation => {
}; };
}; };
const ActionSheet = ({ export default class ActionSheet extends Component {
ref, constructor(props) {
children = <View />, super(props);
animated = true, this.state = {
animationType = 'fade', modalVisible: false,
closeOnPressBack = true, scrollable: false,
gestureEnabled = true, layoutHasCalled: false,
bounceOnOpen = true, };
bounceOffset = 20, this.customComponentHeight;
springOffset = 50, this.prevScroll;
elevation = 5, this.scrollAnimationEndValue;
initialOffsetFromBottom = 0.6, this.hasBounced;
indicatorColor = 'gray', this.scrollViewRef;
customStyles = {backgroundColor: 'white'}, }
overlayColor = 'rgba(0,0,0,0.3)',
onClose = () => {},
onOpen = () => {},
}) => {
const [modalVisible, setModalVisible] = useState(false);
const [scrollable, setScrollable] = useState(false);
const [layoutHasCalled, setLayoutHasCalled] = useState(false);
ActionSheet.customComponentHeight; _setModalVisible = () => {
ActionSheet.prevScroll; if (!this.state.modalVisible) {
ActionSheet.scrollAnimationEndValue; this.setState({
ActionSheet.hasBounced; modalVisible: true,
scrollable: this.props.gestureEnabled,
const _setModalVisible = () => { });
if (!modalVisible) {
setModalVisible(true);
if (gestureEnabled) {
setScrollable(true);
}
} else { } else {
_hideModal(); this._hideModal();
} }
}; };
const _hideModal = () => { _hideModal = () => {
_scrollTo(0); this._scrollTo(0);
setTimeout(() => { setTimeout(() => {
setLayoutHasCalled(false); this.setState(
setModalVisible(false); {
ActionSheet.customComponentHeight = null; modalVisible: false,
ActionSheet.prevScroll = null; layoutHasCalled: false,
ActionSheet.scrollAnimationEndValue = null; },
ActionSheet.hasBounced = null; () => {
if (typeof onClose === 'function') onClose(); if (typeof this.props.onClose === 'function') this.props.onClose();
},
);
}, 150); }, 150);
}; };
const _showModal = event => { _showModal = event => {
if (layoutHasCalled) { let {gestureEnabled, bounceOffset, initialOffsetFromBottom} = this.props;
let addFactor = deviceHeight * 0.1;
let height = event.nativeEvent.layout.height;
console.log('layout called again');
if (this.state.layoutHasCalled) {
let diff;
if (height > this.customComponentHeight) {
diff = height - this.customComponentHeight;
this._scrollTo(this.prevScroll + diff);
console.log(this.prevScroll);
this.customComponentHeight = height;
} else {
diff = this.customComponentHeight - height;
this._scrollTo(this.prevScroll - diff);
this.customComponentHeight = height;
}
return; return;
} else { } else {
ActionSheet.customComponentHeight = event.nativeEvent.layout.height; this.customComponentHeight = height;
let addFactor = deviceHeight * 0.1;
_scrollTo( this._scrollTo(
gestureEnabled gestureEnabled
? ActionSheet.customComponentHeight * initialOffsetFromBottom + ? this.customComponentHeight * initialOffsetFromBottom +
addFactor + addFactor +
bounceOffset bounceOffset
: ActionSheet.customComponentHeight + bounceOffset, : this.customComponentHeight + bounceOffset,
); );
this.setState({
setLayoutHasCalled(true); layoutHasCalled: true,
});
} }
}; };
const _onScrollBeginDrag = event => { _onScrollBeginDrag = event => {
let verticalOffset = event.nativeEvent.contentOffset.y; let verticalOffset = event.nativeEvent.contentOffset.y;
ActionSheet.prevScroll = verticalOffset;
this.prevScroll = verticalOffset;
}; };
const _onScrollEndDrag = event => { _onScrollEndDrag = event => {
let {springOffset} = this.props;
let verticalOffset = event.nativeEvent.contentOffset.y; let verticalOffset = event.nativeEvent.contentOffset.y;
if (ActionSheet.prevScroll < verticalOffset) { if (this.prevScroll < verticalOffset) {
if (verticalOffset - ActionSheet.prevScroll > springOffset * 0.75) { if (verticalOffset - this.prevScroll > springOffset * 0.75) {
let addFactor = deviceHeight * 0.1; let addFactor = deviceHeight * 0.1;
_scrollTo(ActionSheet.customComponentHeight + addFactor); this._scrollTo(this.customComponentHeight + addFactor);
} else { } else {
_scrollTo(ActionSheet.prevScroll); this._scrollTo(this.prevScroll);
} }
} else { } else {
if (ActionSheet.prevScroll - verticalOffset > springOffset) { if (this.prevScroll - verticalOffset > springOffset) {
_hideModal(); this._hideModal();
} else { } else {
_scrollTo(ActionSheet.prevScroll); this._scrollTo(this.prevScroll);
} }
} }
}; };
const _scrollTo = (y, bouncing) => { _scrollTo = (y, bouncing) => {
let {bounceOffset, bounceOnOpen} = this.props;
this.hasBounced = false;
if (!bouncing && bounceOnOpen) { if (!bouncing && bounceOnOpen) {
ActionSheet.scrollAnimationEndValue = y + bounceOffset; this.scrollAnimationEndValue = y + bounceOffset;
} else { } else {
ActionSheet.scrollAnimationEndValue = y; this.scrollAnimationEndValue = y;
} }
ActionSheet.hasBounced = false;
scrollViewRef.scrollTo({ this.scrollViewRef.scrollTo({
x: 0, x: 0,
y: ActionSheet.scrollAnimationEndValue, y: this.scrollAnimationEndValue,
animated: true, animated: true,
}); });
}; };
const _onTouchMove = () => { _onTouchMove = () => {
setScrollable(false); this._hideModal();
this.setState({
scrollable: false,
});
}; };
const _onTouchStart = () => { _onTouchStart = () => {
setScrollable(false); this._hideModal();
this.setState({
scrollable: false,
});
}; };
const _onTouchEnd = () => { _onTouchEnd = () => {
if (gestureEnabled) { if (this.props.gestureEnabled) {
setScrollable(true); this.setState({
scrollable: true,
});
} }
}; };
const _onScrollEndAnimation = () => { _onScrollEndAnimation = event => {
if (!ActionSheet.hasBounced) { this.prevScroll = event.nativeEvent.contentOffset.y;
_scrollTo(ActionSheet.scrollAnimationEndValue - bounceOffset, true);
ActionSheet.hasBounced = true; let {bounceOffset, bounceOnOpen} = this.props;
if (!this.hasBounced && bounceOnOpen) {
this._scrollTo(this.scrollAnimationEndValue - bounceOffset, true);
this.hasBounced = true;
} }
}; };
return ( render() {
<Modal let {scrollable, modalVisible} = this.state;
ref={ref} let {
visible={modalVisible} animationType,
animationType={animationType} animated,
animated={animated} onOpen,
onShow={() => onOpen} closeOnPressBack,
onRequestClose={() => { overlayColor,
if (closeOnPressBack) _hideModal(); bounceOnOpen,
}} gestureEnabled,
transparent={true}> elevation,
<View style={[styles.parentContainer, {backgroundColor: overlayColor}]}> indicatorColor,
<ScrollView children,
bounces={false} customStyles,
ref={ref => (scrollViewRef = ref)} } = this.props;
showsVerticalScrollIndicator={false}
scrollEnabled={scrollable} return (
onScrollBeginDrag={_onScrollBeginDrag} <Modal
onScrollEndDrag={_onScrollEndDrag} visible={modalVisible}
onMomentumScrollEnd={() => { animationType={animationType}
if (bounceOnOpen) { animated={animated}
_onScrollEndAnimation(); onShow={() => onOpen}
} onRequestClose={() => {
}} if (closeOnPressBack) this._hideModal();
onScrollAnimationEnd={_onScrollEndAnimation} }}
onTouchEnd={_onTouchEnd} transparent={true}>
overScrollMode="always" <View style={[styles.parentContainer, {backgroundColor: overlayColor}]}>
style={[styles.scrollview]}> <KeyboardAvoidingView
<View
onTouchMove={_onTouchMove}
onTouchStart={_onTouchStart}
onTouchEnd={_onTouchEnd}
style={{ style={{
height: deviceHeight * 1.1,
width: '100%', width: '100%',
}}> }}
<TouchableOpacity enabled={Platform.OS === 'ios' ? true : false}
onPress={_hideModal} behavior="position">
onLongPress={_hideModal} <ScrollView
style={{ bounces={false}
height: deviceHeight, ref={ref => (this.scrollViewRef = ref)}
width: '100%', showsVerticalScrollIndicator={false}
}} scrollEnabled={scrollable}
/> onScrollBeginDrag={this._onScrollBeginDrag}
</View> onScrollEndDrag={this._onScrollEndDrag}
<View onMomentumScrollEnd={this._onScrollEndAnimation}
onLayout={_showModal} onScrollAnimationEnd={this._onScrollEndAnimation}
style={[ onTouchEnd={this._onTouchEnd}
styles.container, overScrollMode="always"
customStyles, style={[styles.scrollview]}>
{...getElevation(elevation)},
]}>
{gestureEnabled ? (
<View <View
style={[styles.indicator, {backgroundColor: indicatorColor}]} onTouchMove={this._onTouchMove}
/> onTouchStart={this._onTouchStart}
) : null} onTouchEnd={this._onTouchEnd}
style={{
height: deviceHeight * 1.1,
width: '100%',
}}>
<TouchableOpacity
onPress={this._hideModal}
onLongPress={this._hideModal}
style={{
height: deviceHeight,
width: '100%',
}}
/>
</View>
<View
onLayout={this._showModal}
style={[
styles.container,
customStyles,
{...getElevation(elevation)},
]}>
{gestureEnabled ? (
<View
style={[
styles.indicator,
{backgroundColor: indicatorColor},
]}
/>
) : null}
{children} {children}
</View> </View>
</ScrollView> </ScrollView>
</View> </KeyboardAvoidingView>
</Modal> </View>
); </Modal>
);
}
}
ActionSheet.defaultProps = {
children: <View />,
animated: true,
animationType: 'fade',
closeOnPressBack: true,
gestureEnabled: true,
bounceOnOpen: true,
bounceOffset: 20,
springOffset: 50,
elevation: 5,
initialOffsetFromBottom: 0.6,
indicatorColor: 'gray',
customStyles: {},
overlayColor: 'rgba(0,0,0,0.3)',
onClose: () => {},
onOpen: () => {},
};
ActionSheet.propTypes = {
children: PropTypes.node,
animated: PropTypes.bool,
animationType: PropTypes.oneOf(['none', 'slide', 'fade']),
closeOnPressBack: PropTypes.bool,
gestureEnabled: PropTypes.bool,
bounceOnOpen: PropTypes.bool,
bounceOffset: PropTypes.number,
springOffset: PropTypes.number,
elevation: PropTypes.number,
initialOffsetFromBottom: PropTypes.number,
indicatorColor: PropTypes.string,
customStyles: PropTypes.object,
overlayColor: PropTypes.string,
onClose: PropTypes.func,
onOpen: PropTypes.func,
}; };
export default ActionSheet;

View File

@@ -1,4 +1,4 @@
import React, {useState} from 'react'; import React, {useState, useEffect} from 'react';
import { import {
View, View,
Text, Text,
@@ -28,7 +28,7 @@ const h = Dimensions.get('window').height;
let tagsInputRef; let tagsInputRef;
export const ActionSheetComponent = ({ export const ActionSheetComponent = ({
close = () => {}, close = () => {},
item = {}, item,
setWillRefresh = value => {}, setWillRefresh = value => {},
hasColors = false, hasColors = false,
hasTags = false, hasTags = false,
@@ -39,6 +39,10 @@ export const ActionSheetComponent = ({
const [focused, setFocused] = useState(false); const [focused, setFocused] = useState(false);
const [note, setNote] = useState(item ? item : {}); const [note, setNote] = useState(item ? item : {});
useEffect(() => {
setNote({...item});
}, [item]);
let tagToAdd = null; let tagToAdd = null;
let backPressCount = 0; let backPressCount = 0;
@@ -257,6 +261,10 @@ export const ActionSheetComponent = ({
return ( return (
<View <View
onLayout={() => {
console.log(item);
setNote({...item});
}}
style={{ style={{
paddingBottom: 15, paddingBottom: 15,
backgroundColor: colors.bg, backgroundColor: colors.bg,