Last active
February 7, 2023 05:58
-
-
Save jfaverie/d98d8f60a510e3b68abeffb43a77d47a to your computer and use it in GitHub Desktop.
This file contains hidden or 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 from "react"; | |
import { | |
LayoutChangeEvent, | |
PanResponder, | |
PanResponderGestureState | |
} from "react-native"; | |
import styled from "styled-components"; | |
type StateType = { | |
barHeight: number | null, | |
deltaValue: number, | |
value: number | |
}; | |
const initialValue = 0; | |
const min = 0; | |
const max = 100; | |
const CIRCLE_DIAMETER = 50; | |
export default class Slider extends React.Component<{}, StateType> { | |
state = { | |
barHeight: null, | |
deltaValue: 0, | |
value: initialValue | |
}; | |
panResponder = PanResponder.create({ | |
onMoveShouldSetPanResponderCapture: () => true, | |
onPanResponderMove: (_, gestureState) => this.onMove(gestureState), | |
onPanResponderRelease: () => this.onEndMove(), | |
onPanResponderTerminate: () => {} | |
}); | |
onMove(gestureState: PanResponderGestureState) { | |
const { barHeight } = this.state; | |
const newDeltaValue = this.getValueFromBottomOffset( | |
-gestureState.dy, | |
barHeight, | |
min, | |
max | |
); | |
this.setState({ | |
deltaValue: newDeltaValue | |
}); | |
} | |
onEndMove() { | |
const { value, deltaValue } = this.state; | |
this.setState({ value: value + deltaValue, deltaValue: 0 }); | |
} | |
onBarLayout = (event: LayoutChangeEvent) => { | |
const { height: barHeight } = event.nativeEvent.layout; | |
this.setState({ barHeight }); | |
}; | |
capValueWithinRange = (value: number, range: number[]) => { | |
if (value < range[0]) return range[0]; | |
if (value > range[1]) return range[1]; | |
return value; | |
}; | |
getValueFromBottomOffset = ( | |
offset: number, | |
barHeight: number | null, | |
rangeMin: number, | |
rangeMax: number | |
) => { | |
if (barHeight === null) return 0; | |
return ((rangeMax - rangeMin) * offset) / barHeight; | |
}; | |
getBottomOffsetFromValue = ( | |
value: number, | |
rangeMin: number, | |
rangeMax: number, | |
barHeight: number | null | |
) => { | |
if (barHeight === null) return 0; | |
const valueOffset = value - rangeMin; | |
const totalRange = rangeMax - rangeMin; | |
const percentage = valueOffset / totalRange; | |
return barHeight * percentage; | |
}; | |
render() { | |
const { value, deltaValue, barHeight } = this.state; | |
const cappedValue = this.capValueWithinRange(value + deltaValue, [ | |
min, | |
max | |
]); | |
const bottomOffset = this.getBottomOffsetFromValue( | |
cappedValue, | |
min, | |
max, | |
barHeight | |
); | |
return ( | |
<PageContainer> | |
<Value>{Math.floor(cappedValue)}</Value> | |
<Container> | |
<BarContainer> | |
<Bar onLayout={this.onBarLayout} /> | |
<Circle | |
bottomOffset={bottomOffset} | |
{...this.panResponder.panHandlers} | |
/> | |
</BarContainer> | |
</Container> | |
</PageContainer> | |
); | |
} | |
} | |
const PageContainer = styled.View` | |
background-color: black; | |
flex-grow: 1; | |
align-self: stretch; | |
align-items: center; | |
padding-vertical: 20; | |
`; | |
const Container = styled.View` | |
flex-grow: 1; | |
align-self: stretch; | |
justify-content: center; | |
flex-direction: row; | |
`; | |
const Value = styled.Text` | |
color: white; | |
`; | |
const BarContainer = styled.View` | |
width: ${CIRCLE_DIAMETER}; | |
align-items: center; | |
padding-vertical: ${CIRCLE_DIAMETER / 2}; | |
margin-horizontal: 20; | |
`; | |
const Bar = styled.View` | |
width: 2; | |
background-color: white; | |
flex-grow: 1; | |
`; | |
const Circle = styled.View` | |
border-radius: ${CIRCLE_DIAMETER / 2}; | |
width: ${CIRCLE_DIAMETER}; | |
height: ${CIRCLE_DIAMETER}; | |
background-color: white; | |
position: absolute; | |
bottom: ${props => props.bottomOffset}; | |
`; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
model component is not working in ios release.