import React, { Component } from 'react';
import {
View,
PanResponder,
StyleSheet,
Text,
Dimensions,
Animated,
Easing
} from 'react-native';
/* 數(shù)據(jù)相關(guān):
*
*/
// const labels = ['0', '100', '200', '300', '400', '600', '1000', '不限'];
const labels = ['0', '200', '400', '600', '1000', '不限'];
/* 尺寸轉(zhuǎn)換方法
* _px: 以750位基準(zhǔn)的轉(zhuǎn)屏幕
* _pos: 以屏幕為基準(zhǔn)的轉(zhuǎn)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)
}
/* 尺寸相關(guān)
* excludeWidth: 距離屏幕左右邊界的距離,不觸發(fā)點擊滑動等事件的區(qū)域
* unitWidth: 每一個單位的總寬度,有效區(qū)域等分后的寬度
* labelWidth: 每一個單位的有效的點擊寬度
* sliderWidth: 滑塊的寬度
* sliderInitialLeft: 第一個滑塊的left
*/
const excludeWidth = 75;
const unitWidth = (750 - excludeWidth * 2) / labels.length; //100
const labelWidth = unitWidth - 20; // 兩個標(biāo)簽核心之間間隙 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 雙滑塊滑動條
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門欠雌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疙筹,你說我怎么就攤上這事富俄。” “怎么了而咆?”我有些...
- 文/不壞的土叔 我叫張陵霍比,是天一觀的道長。 經(jīng)常有香客問我暴备,道長悠瞬,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任馍驯,我火速辦了婚禮暇唾,結(jié)果婚禮上唯鸭,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好羹奉,可當(dāng)我...
- 文/花漫 我一把揭開白布浆兰。 她就那樣靜靜地躺著雨饺,像睡著了一般荐吉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝗拿,一...
- 文/蒼蘭香墨 我猛地睜開眼玻淑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呀伙?” 一聲冷哼從身側(cè)響起补履,我...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡雨女,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 年R本政府宣布乱灵,位于F島的核電站,受9級特大地震影響七冲,放射性物質(zhì)發(fā)生泄漏痛倚。R本人自食惡果不足惜,卻給世界環(huán)境...
- 文/蒙蒙 一澜躺、第九天 我趴在偏房一處隱蔽的房頂上張望蝉稳。 院中可真熱鬧,春花似錦掘鄙、人聲如沸耘戚。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽收津。三九已至,卻和暖如春浊伙,著一層夾襖步出監(jiān)牢的瞬間撞秋,已是汗流浹背。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- input range做滑動條,改變滑動條和滑塊的樣式: 動態(tài)改變滑塊的位置和進(jìn)度條的長度: * input ra...
- 問題: 1伸蚯、滑塊大小: 滑塊大小不能改變简烤,但是能通過設(shè)置圖片改變 2剂邮、不能滑動,滑動沒反應(yīng) 需要設(shè)置寬高:嵴臁:寬度不...
- react native 要實現(xiàn)頁面滑動枉侧,需要添加ScrollView標(biāo)簽引瀑,否則無法滑動頁面,頁面內(nèi)容顯示不全 這...
- 1.背景 ??在文章例子中的RN(以下用RN表示React Native)版本是0.43.3榨馁。RN官方和非官方提供...