import React, { Component } from 'react';
import {
View,
PanResponder,
StyleSheet,
Text,
Dimensions,
Animated,
Easing
} from 'react-native';
/* 数据相关:
*
*/
// const labels = ['0', '100', '200', '300', '400', '600', '1000', '不限'];
const labels = ['0', '200', '400', '600', '1000', '不限'];
/* 尺寸转换方法
* _px: 以750位基准的转屏幕
* _pos: 以屏幕为基准的转750
*/
const dw = Dimensions.get('window').width;
const ratioDeps750 = dw / 750;
const _px = function getRpx(value) {
return Math.floor(value * ratioDeps750);
}
const _pos = function getPos(value) {
return Math.floor(value / ratioDeps750)
}
/* 尺寸相关
* excludeWidth: 距离屏幕左右边界的距离,不触发点击滑动等事件的区域
* unitWidth: 每一个单位的总宽度,有效区域等分后的宽度
* labelWidth: 每一个单位的有效的点击宽度
* sliderWidth: 滑块的宽度
* sliderInitialLeft: 第一个滑块的left
*/
const excludeWidth = 75;
const unitWidth = (750 - excludeWidth * 2) / labels.length; //100
const labelWidth = unitWidth - 20; // 两个标签核心之间间隙 40
const sliderWidth = 60;
const halfUnitWidth = unitWidth / 2; // slider:halfUnitWidth - sliderWidth / 2; line:halfUnitWidth
const duration = 300;
const easing = Easing.linear;
export default class App extends Component {
constructor(props) {
super(props)
let leftBoundaryForLeft = 0;
let rightBoundaryForLeft = 0;
let validPosForLeft = 0;
let leftBoundaryForRight = 0;
let rightBoundaryForRight = 0;
let validPosForRight = 0;
this.state = {
leftIndex: 0,
rightIndex: 0,
leftPos: new Animated.Value(0),
rightPos: new Animated.Value(0)
}
this._leftSliderPanResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderTerminationRequest: (evt, gestureState) => true,
onShouldBlockNativeResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
// 左边界
leftBoundaryForLeft = excludeWidth + halfUnitWidth;
// 右边界
rightBoundaryForLeft = this.state.rightIndex * unitWidth + excludeWidth + halfUnitWidth;
validPosForLeft = _pos(gestureState.x0)
},
onPanResponderMove: (evt, gestureState) => {
//手势中心点
let centerX = _pos(gestureState.moveX)
if (centerX >= leftBoundaryForLeft && centerX <= rightBoundaryForLeft - unitWidth) {
this.state.leftPos.setValue(centerX - excludeWidth);
validPosForLeft = centerX;
let posIndex = Math.floor((validPosForLeft - excludeWidth) / unitWidth);
this.setState({
leftIndex: posIndex
})
}
},
onPanResponderRelease: (evt, gestureState) => {
let posIndex = Math.floor((validPosForLeft - excludeWidth) / unitWidth);
this.setPos({ leftIndex: posIndex })
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
this._rightSliderPanResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderTerminationRequest: (evt, gestureState) => true,
onShouldBlockNativeResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
// 左边界
leftBoundaryForRight = this.state.leftIndex * unitWidth + excludeWidth + halfUnitWidth;
// 右边界
rightBoundaryForRight = 750 - excludeWidth - halfUnitWidth;
validPosForRight = _pos(gestureState.x0)
},
onPanResponderMove: (evt, gestureState) => {
//手势中心点
let centerX = _pos(gestureState.moveX)
if (centerX >= leftBoundaryForRight + unitWidth && centerX <= rightBoundaryForRight) {
this.state.rightPos.setValue(centerX - excludeWidth);
validPosForRight = centerX;
let posIndex = Math.floor((validPosForRight - excludeWidth) / unitWidth);
this.setState({
rightIndex: posIndex
})
}
},
onPanResponderRelease: (evt, gestureState) => {
let posIndex = Math.floor((validPosForRight - excludeWidth) / unitWidth);
this.setPos({ rightIndex: posIndex })
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
this._viewPanResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderTerminationRequest: (evt, gestureState) => true,
onShouldBlockNativeResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
},
onPanResponderMove: (evt, gestureState) => {
},
onPanResponderRelease: (evt, gestureState) => {
if (gestureState.moveX) {
return;
}
let x = _pos(gestureState.x0);
if ((x - excludeWidth) % unitWidth < (unitWidth - labelWidth) / 2 || (x - excludeWidth) % unitWidth > unitWidth - (unitWidth - labelWidth) / 2) {
console.log('无效点')
return;
}
let posIndex = Math.floor((x - excludeWidth) / unitWidth);
let { leftIndex, rightIndex } = this.state;
let leftPos = leftIndex * unitWidth + halfUnitWidth;
let rightPos = rightIndex * unitWidth + halfUnitWidth;
// 距离左边的点更近
if (Math.abs(x - excludeWidth - leftPos) <= Math.abs(x - excludeWidth - rightPos)) {
this.setPos({ leftIndex: posIndex === rightIndex ? posIndex - 1 : posIndex })
} else {
this.setPos({ rightIndex: posIndex === leftIndex ? posIndex + 1 : posIndex })
}
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
render() {
let { leftPos, rightPos, leftIndex, rightIndex } = this.state;
return (
<View style={styles.container}>
<View style={styles.content}>
<View {...this._viewPanResponder.panHandlers} style={styles.pan} >
<View style={styles.labels}>
{labels.map((item, index) => {
return <Text key={index} style={{ ...StyleSheet.flatten(styles.label), color: index < leftIndex || index > rightIndex ? '#898989' : '#3F70C1' }}>{item}</Text>
})}
</View>
<View style={styles.lines}>
<View style={styles.line} />
<Animated.View style={{
...StyleSheet.flatten(styles.hl_line),
left: leftPos.interpolate({
inputRange: [halfUnitWidth, labels.length * unitWidth - halfUnitWidth],
outputRange: [_px(halfUnitWidth), _px(labels.length * unitWidth - halfUnitWidth)]//
}),
right: rightPos.interpolate({
inputRange: [halfUnitWidth, labels.length * unitWidth - halfUnitWidth],
outputRange: [_px(labels.length * unitWidth - halfUnitWidth), _px(halfUnitWidth)]//
})
}} />
</View>
</View>
<Animated.Image {...this._leftSliderPanResponder.panHandlers} source={images.slider} style={{
...StyleSheet.flatten(styles.slider),
left: leftPos.interpolate({
inputRange: [halfUnitWidth, labels.length * unitWidth - halfUnitWidth],
outputRange: [_px(halfUnitWidth), _px(labels.length * unitWidth - halfUnitWidth)]//
}),
}} />
<Animated.Image {...this._rightSliderPanResponder.panHandlers} source={images.slider} style={{
...StyleSheet.flatten(styles.slider),
left: rightPos.interpolate({
inputRange: [halfUnitWidth, labels.length * unitWidth - halfUnitWidth],
outputRange: [_px(halfUnitWidth), _px(labels.length * unitWidth - halfUnitWidth)]//
}),
}} />
</View>
<Text>{leftIndex}</Text>
<Text>{rightIndex}</Text>
</View>
);
}
componentDidMount() {
this.setPos({ leftIndex: 0, rightIndex: labels.length - 1 })
}
setPos({ leftIndex, rightIndex }) {
if (leftIndex >= 0) {
Animated.parallel([
Animated.timing(this.state.leftPos, {
toValue: leftIndex * unitWidth + halfUnitWidth,
duration,
easing,
})
]).start(() => {
this.setState({
leftIndex: leftIndex
})
})
}
if (rightIndex >= 0) {
Animated.parallel([
Animated.timing(this.state.rightPos, {
toValue: rightIndex * unitWidth + halfUnitWidth,
duration,
easing,
}),
]).start(() => {
this.setState({
rightIndex: rightIndex
})
})
}
}
}
const styles = StyleSheet.create({
container: {
height: _px(180),
backgroundColor: '#fff'
},
content: {
backgroundColor: '#fff',
height: _px(180),
position: 'relative',
marginHorizontal: _px(excludeWidth),
marginVertical: _px(30),
height: _px(120),
},
pan: {
backgroundColor: '#fff'
},
labels: {
height: _px(60),
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center'
},
label: {
width: _px(labelWidth),
textAlign: 'center',
},
lines: {
height: _px(60),
justifyContent: 'center',
},
line: {
position: 'absolute',
backgroundColor: '#ddd',
height: _px(4),
left: _px(halfUnitWidth),
right: _px(halfUnitWidth)
},
hl_line: {
position: 'absolute',
backgroundColor: '#3F70C1',
height: _px(4),
},
slider: {
width: _px(sliderWidth),
height: _px(sliderWidth),
resizeMode: 'contain',
position: 'absolute',
top: _px(90),
transform: [{
translateX: -_px(sliderWidth / 2),
}, {
translateY: -_px(sliderWidth / 2),
}]
}
});
const images = {
slider: require('./img/slider.png')
}
React Native 双滑块滑动条
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- input range做滑动条,改变滑动条和滑块的样式: 动态改变滑块的位置和进度条的长度: * input ra...
- 问题: 1、滑块大小: 滑块大小不能改变,但是能通过设置图片改变 2、不能滑动,滑动没反应 需要设置宽高!:宽度不...
- react native 要实现页面滑动,需要添加ScrollView标签,否则无法滑动页面,页面内容显示不全 这...
- 1.背景 在文章例子中的RN(以下用RN表示React Native)版本是0.43.3。RN官方和非官方提供...