纯tsx复制即用
import {Animated, PanResponder, StyleSheet, View} from "react-native";
import * as React from "react";
import {useRef, useState} from "react";
interface NJSlideViewProps {
iWidth: number,
iHeight: number | 15,
value: number | 0.5,
progress: (progress: number, scroll: boolean) => void
color?: Array<string> | ["white", "red"],
}
export function NJSlideView(props: NJSlideViewProps) {
let color = ["white", "red"]
let value=0.5
if (props.color !== undefined) {
color = props.color
}
if (props.value!==undefined){
value=props.value>1?1:props.value
}
const [parentX, setParentX] = useState(0)
const pan = useRef(new Animated.ValueXY({x: (props.iWidth - props.iHeight) * value+props.iHeight/2, y: 0})).current;
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, g) => {
// console.log(e.nativeEvent)
// console.log(e.nativeEvent.pageX-parentX)
pan.setOffset({
x: e.nativeEvent.pageX - parentX ,
y: 0
})
},
onPanResponderMove: (event, g) => {
//滑动计算 偏移props.iHeight/2个单位
let dx = parentX + props.iHeight/2 < g.x0 + g.dx
? g.x0 + g.dx < parentX + props.iWidth-props.iHeight/2
? g.dx
: parentX + props.iWidth- props.iHeight/2 - g.x0
: parentX + props.iHeight/2 - g.x0
pan.setValue({
x: dx,
y: 0
})
},
onPanResponderRelease: (event,g) => {
pan.flattenOffset()
},
});
return (
<View
onLayout={event => {
console.log(event.nativeEvent)
setParentX(event.nativeEvent.layout.x)
}}
style={[NJSlideViewStyle.container, {width: props.iWidth,height:props.iHeight}]}>
<View
onTouchStart={e => {
let progress = e.nativeEvent.locationX / props.iWidth
pan.setValue({
x: (props.iWidth - props.iHeight) * progress+props.iHeight/2,
y: 0
})
pan.flattenOffset()
props.progress(progress, false)
}}
style={{width: props.iWidth, height: props.iHeight, position: "absolute", justifyContent: "center"}}>
<View style={{
width: props.iWidth,
height: props.iHeight / 3,
borderRadius: props.iHeight / 3,
backgroundColor: color[0]
}}>
<Animated.View style={{
width: pan.x,
height: props.iHeight / 3,
borderRadius: props.iHeight / 3,
backgroundColor: color[1]
}}/>
</View>
</View>
<Animated.View
{...panResponder.panHandlers}
style={
[NJSlideViewStyle.seekbar,
{
height: props.iHeight,
width: props.iHeight,
marginLeft: -props.iHeight/2,
borderRadius:props.iHeight,
backgroundColor: color[1]
},
pan.getLayout()]}>
</Animated.View>
</View>
)
}
const NJSlideViewStyle = StyleSheet.create({
container: {
height: 30,
alignItems: "flex-start",
justifyContent: "center",
},
seekbar: {
width: 30,
height: 30,
borderRadius: 20,
}
})
使用方法
<NJSlideView
value={0.01}
iWidth={width-80}
iHeight={30}
color={["white","red"]}
progress={(progress, scroll) => {
console.log(progress)
}}/>
<NJSlideView
value={0.99}
iWidth={width-80}
iHeight={10}
color={["white","#0cee12"]}
progress={(progress, scroll) => {
console.log(progress)
}}/>
效果
Simulator Screen Shot - iPhone 13 - 2021-12-10 at 14.51.11.png
目前的bug是当组件被一个没有具体宽带的View 包裹时,拖拽进度条按钮的偏移量会计算出错。受前面bug的影响拖拽实时的进度我没计算,拖拽完成的进度我也没计算。
我刚开始的写的这个组件是希望能实现年龄段的选择,(就是能在一条线上,选出最大年龄,和最小年龄的功能)。不知道把头发干秃能不能做出来。