Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backdrop enhancements #130

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ animatedValue|Animated.Value|An **Animated.Value** number between the top and bo
|showBackdrop|boolean|Controls the visibility of backdrop. Default `true`.
|allowMomentum|boolean|If `false`, panel will not continue to move when you release your finger.
|allowDragging|boolean|Default `true`. Setting this to `false` to disable dragging.
|stopFlickOnBackdropTap|boolean|Default `true`. Setting this to `false` to prevent the user to stop the flicking action while the container is sliding up.
|hideOnBackdropTap|boolean|Default `true`. Setting this to `false` to prevent the hide of the container when the user taps the backdrop.
|onBackButtonPress|() => boolean|By default when you press back button (Android) the panel will be closed (Move to `bottom` position of `draggableRange`). Implement this function if you want to custom the behavior. Returning `true` means the event has been handled.
|onDragStart|(position: number, gestureState: GestureState) => void|Called when the panel is about to start dragging.
|onDragEnd|(position: number: gestureState: GestureState) => void|Called when you release your finger.
|onMomentumDragStart|(position: number) => void|Called when the momentum drag starts. Works exactly the same way of [ScrollView#onMomentumScrollBegin](https://facebook.github.io/react-native/docs/scrollview#onmomentumscrollbegin).
|onMomentumDragEnd|(position: number) => void|Called when the momentum drag ends. Works exactly the same way of [ScrollView#onMomentumScrollEnd](https://facebook.github.io/react-native/docs/scrollview#onmomentumscrollend).
|onBackdropTouchStart|() => void|Called when user taps the backdrop when the container is sliding up.
|onBackdropTouchEnd|() => void|Called when user taps the backdrop when the container is fully opened.
|children|React.Element \| Function|Accepts passing a function as component. Invoked with `dragHandlers` (that can be passed into another View like this `<View {...dragHandlers}>`) when the panel is mounted. Useful when you want only a part of your content becomes the drag handler.

A `gestureState` (is forwarded from `PanResponder'`s callbacks) object has the following:
Expand Down
66 changes: 39 additions & 27 deletions SlidingUpPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import closest from './libs/closest'
import measureElement from './libs/measureElement'
import FlickAnimation from './libs/FlickAnimation'
import {statusBarHeight, visibleHeight} from './libs/layout'
import { statusBarHeight, visibleHeight } from './libs/layout'
import * as Constants from './libs/constants'
import styles from './libs/styles'

Expand Down Expand Up @@ -47,9 +47,13 @@ class SlidingUpPanel extends React.PureComponent {
onDragEnd: PropTypes.func,
onMomentumDragStart: PropTypes.func,
onMomentumDragEnd: PropTypes.func,
onBackdropTouchStart: PropTypes.func,
onBackdropTouchEnd: PropTypes.func,
allowMomentum: PropTypes.bool,
allowDragging: PropTypes.bool,
showBackdrop: PropTypes.bool,
hideOnBackdropTap: PropTypes.bool,
stopFlickOnBackdropTap: PropTypes.bool,
backdropOpacity: PropTypes.number,
friction: PropTypes.number,
containerStyle: PropTypes.any,
Expand All @@ -60,19 +64,21 @@ class SlidingUpPanel extends React.PureComponent {
static defaultProps = {
height: usableHeight,
animatedValue: new Animated.Value(0),
draggableRange: {top: usableHeight, bottom: 0},
draggableRange: { top: usableHeight, bottom: 0 },
snappingPoints: [],
minimumVelocityThreshold: Constants.DEFAULT_MINIMUM_VELOCITY_THRESHOLD,
minimumDistanceThreshold: Constants.DEFAULT_MINIMUM_DISTANCE_THRESHOLD,
avoidKeyboard: true,
onBackButtonPress: null,
onDragStart: () => {},
onDragEnd: () => {},
onMomentumDragStart: () => {},
onMomentumDragEnd: () => {},
onDragStart: () => { },
onDragEnd: () => { },
onMomentumDragStart: () => { },
onMomentumDragEnd: () => { },
allowMomentum: true,
allowDragging: true,
showBackdrop: true,
hideOnBackdropTap: true,
stopFlickOnBackdropTap: true,
backdropOpacity: 0.75,
friction: Constants.DEFAULT_FRICTION
}
Expand Down Expand Up @@ -117,7 +123,7 @@ class SlidingUpPanel extends React.PureComponent {
this.hide = this.hide.bind(this)
this.scrollIntoView = this.scrollIntoView.bind(this)

const {top, bottom} = this.props.draggableRange
const { top, bottom } = this.props.draggableRange
const animatedValue = this.props.animatedValue.__getValue()
const initialValue = clamp(animatedValue, bottom, top)

Expand All @@ -126,7 +132,7 @@ class SlidingUpPanel extends React.PureComponent {

this._initialDragPosition = initialValue
this._backdropPointerEvents = this._isAtBottom(initialValue) ? 'none' : 'box-only' // prettier-ignore
this._flick = new FlickAnimation({max: top, min: bottom})
this._flick = new FlickAnimation({ max: top, min: bottom })

this._flickAnimationListener = this._flick.onUpdate(value => {
this.props.animatedValue.setValue(value)
Expand All @@ -142,7 +148,7 @@ class SlidingUpPanel extends React.PureComponent {
prevProps.draggableRange.top !== this.props.draggableRange.top ||
prevProps.draggableRange.bottom !== this.props.draggableRange.bottom
) {
const {top, bottom} = this.props.draggableRange
const { top, bottom } = this.props.draggableRange
const animatedValue = this.props.animatedValue.__getValue()

this._flick.setMax(top)
Expand Down Expand Up @@ -204,7 +210,7 @@ class SlidingUpPanel extends React.PureComponent {
}

_onPanResponderMove(evt, gestureState) {
const {top, bottom} = this.props.draggableRange
const { top, bottom } = this.props.draggableRange
const delta = this._initialDragPosition - gestureState.dy
const newValue = clamp(delta, top, bottom)

Expand All @@ -229,7 +235,7 @@ class SlidingUpPanel extends React.PureComponent {
if (this.props.snappingPoints.length > 0) {
this.props.onMomentumDragStart(animatedValue)

const {top, bottom} = this.props.draggableRange
const { top, bottom } = this.props.draggableRange
const nextPoint = this._flick.predictNextPosition({
fromValue: animatedValue,
velocity: gestureState.vy,
Expand Down Expand Up @@ -278,7 +284,7 @@ class SlidingUpPanel extends React.PureComponent {
this.props.onDragEnd(animatedValue, gestureState)
}

_onAnimatedValueChange({value}) {
_onAnimatedValueChange({ value }) {
const isAtBottom = this._isAtBottom(value)

if (isAtBottom) {
Expand All @@ -293,12 +299,12 @@ class SlidingUpPanel extends React.PureComponent {

if (isAtBottom && this._backdropPointerEvents === 'box-only') {
this._backdropPointerEvents = 'none'
this._backdrop.setNativeProps({pointerEvents: 'none'})
this._backdrop.setNativeProps({ pointerEvents: 'none' })
}

if (!isAtBottom && this._backdropPointerEvents === 'none') {
this._backdropPointerEvents = 'box-only'
this._backdrop.setNativeProps({pointerEvents: 'box-only'})
this._backdrop.setNativeProps({ pointerEvents: 'box-only' })
}
}

Expand Down Expand Up @@ -349,7 +355,7 @@ class SlidingUpPanel extends React.PureComponent {
}

_isInsideDraggableRange(value, gestureState) {
const {top, bottom} = this.props.draggableRange
const { top, bottom } = this.props.draggableRange

if (gestureState.dy > 0) {
return value > bottom
Expand All @@ -359,7 +365,7 @@ class SlidingUpPanel extends React.PureComponent {
}

_isAtBottom(value) {
const {bottom} = this.props.draggableRange
const { bottom } = this.props.draggableRange
return value <= bottom
}

Expand All @@ -385,8 +391,8 @@ class SlidingUpPanel extends React.PureComponent {
return null
}

const {top, bottom} = this.props.draggableRange
const { backdropStyle } = this.props
const { top, bottom } = this.props.draggableRange
const { backdropStyle, onBackdropTouchStart, onBackdropTouchEnd, stopFlickOnBackdropTap, hideOnBackdropTap } = this.props

const backdropOpacity = this.props.animatedValue.interpolate({
inputRange: [bottom, top],
Expand All @@ -399,8 +405,14 @@ class SlidingUpPanel extends React.PureComponent {
key="backdrop"
pointerEvents={this._backdropPointerEvents}
ref={c => (this._backdrop = c)}
onTouchStart={() => this._flick.stop()}
onTouchEnd={() => this.hide()}
onTouchStart={() => {
if (onBackdropTouchStart) onBackdropTouchStart()
if (stopFlickOnBackdropTap) this._flick.stop()
}}
onTouchEnd={() => {
if (onBackdropTouchEnd) onBackdropTouchEnd()
if (hideOnBackdropTap) this.hide()
}}
style={[styles.backdrop, backdropStyle, {opacity: backdropOpacity}]}
/>
)
Expand All @@ -419,7 +431,7 @@ class SlidingUpPanel extends React.PureComponent {
extrapolate: 'clamp'
})

const transform = {transform: [{translateY}]}
const transform = { transform: [{ translateY }] }

const animatedContainerStyles = [
styles.animatedContainer,
Expand Down Expand Up @@ -456,20 +468,20 @@ class SlidingUpPanel extends React.PureComponent {

show(mayBeValueOrOptions) {
if (!mayBeValueOrOptions) {
const {top} = this.props.draggableRange
return this._triggerAnimation({toValue: top})
const { top } = this.props.draggableRange
return this._triggerAnimation({ toValue: top })
}

if (typeof mayBeValueOrOptions === 'object') {
return this._triggerAnimation(mayBeValueOrOptions)
}

return this._triggerAnimation({toValue: mayBeValueOrOptions})
return this._triggerAnimation({ toValue: mayBeValueOrOptions })
}

hide() {
const {bottom} = this.props.draggableRange
this._triggerAnimation({toValue: bottom})
const { bottom } = this.props.draggableRange
this._triggerAnimation({ toValue: bottom })
}

async scrollIntoView(node, options = {}) {
Expand All @@ -480,7 +492,7 @@ class SlidingUpPanel extends React.PureComponent {
// Stop any animation when the keyboard starts showing
this._flick.stop()

const {y} = await measureElement(node)
const { y } = await measureElement(node)
const extraMargin = options.keyboardExtraMargin || Constants.KEYBOARD_EXTRA_MARGIN // prettier-ignore
const keyboardActualPos = this._keyboardYPosition - extraMargin

Expand Down