313 lines
8.8 KiB
JavaScript
313 lines
8.8 KiB
JavaScript
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
Modal,
|
|
PanResponder,
|
|
Dimensions,
|
|
} from "react-native";
|
|
import React, { useState, useEffect, useRef } from "react";
|
|
import { useTailwind } from "tailwind-rn";
|
|
import { Image } from "expo-image";
|
|
export default function MySlider({
|
|
lower_bound,
|
|
upper_bound,
|
|
step,
|
|
unit,
|
|
lable,
|
|
height = 60,
|
|
width = Dimensions.get("window").width - 48,
|
|
onChange,
|
|
onAfterChange = () => {},
|
|
defaultValue = 0,
|
|
disabled = false,
|
|
thumbSize = 25,
|
|
stepValues = [],
|
|
itemKey,
|
|
hasInfinity,
|
|
leftValue = 0,
|
|
rightValue = 0,
|
|
thumbImage = null,
|
|
maximumTrackTintColor = "#dcdbdb",
|
|
minimumTrackTintColor = "#577BFF",
|
|
processHeight = 7,
|
|
}) {
|
|
// const leftProcess = useRef(0);
|
|
// const rightProcess = useRef(0);
|
|
|
|
const [leftProcess, setLeftProcess] = useState(0);
|
|
const [rightProcess, setRightProcess] = useState(0);
|
|
const [stepNum, setStepNum] = useState(stepValues.length - 1);
|
|
const [processWidth, setProcessWidth] = useState(330);
|
|
const tailwind = useTailwind();
|
|
const leftWatcher = useRef(null);
|
|
const rightWatcher = useRef(null);
|
|
useEffect(() => {
|
|
leftWatcher.current = PanResponder.create({
|
|
// 建立监视器
|
|
onStartShouldSetPanResponder: () => true,
|
|
onPanResponderGrant: _onPanResponderGrantLeft, // 按下
|
|
onPanResponderMove: _onPanResponderMoveLeft, // 移动
|
|
onPanResponderEnd: _onPanResponderEndLeft, // 结束
|
|
});
|
|
rightWatcher.current = PanResponder.create({
|
|
// 建立监视器
|
|
onStartShouldSetPanResponder: () => true,
|
|
onPanResponderGrant: _onPanResponderGrantRight, // 按下
|
|
onPanResponderMove: _onPanResponderMoveRight, // 移动
|
|
onPanResponderEnd: _onPanResponderEndRight, // 结束
|
|
});
|
|
setProcessWidth(width - thumbSize * 2);
|
|
}, []);
|
|
useEffect(() => {
|
|
// if(itemKey)
|
|
const currentLeftProcess = 0;
|
|
const currentRightProcess =
|
|
(stepValues.indexOf(rightValue) * step - lower_bound) /
|
|
(upper_bound - lower_bound);
|
|
setLeftProcess(currentLeftProcess);
|
|
setRightProcess(currentRightProcess);
|
|
}, [leftValue, rightValue]);
|
|
// useEffect(() => {
|
|
|
|
// }, [leftProcess, rightProcess]);
|
|
// 左侧滑块事件
|
|
const _onPanResponderGrantLeft = (e, gestureState) => {
|
|
const process = (gestureState.x0 - 40 - thumbSize / 2) / processWidth;
|
|
_changeProcess(process, "left");
|
|
};
|
|
|
|
const _onPanResponderEndLeft = (e, gestureState) => {
|
|
if (onAfterChange) {
|
|
onAfterChange(gestureState.x0);
|
|
}
|
|
};
|
|
const _onPanResponderMoveLeft = (e, gestureState) => {
|
|
const process =
|
|
(gestureState.x0 - 40 - thumbSize / 2 + gestureState.dx) / processWidth;
|
|
_changeProcess(process, "left");
|
|
};
|
|
|
|
// 右侧滑块事件
|
|
const _onPanResponderGrantRight = (e, gestureState) => {
|
|
const process = (gestureState.x0 - 40 - thumbSize / 2) / processWidth;
|
|
_changeProcess(process, "right");
|
|
};
|
|
|
|
const _onPanResponderEndRight = (e, gestureState) => {
|
|
if (onAfterChange) {
|
|
onAfterChange(gestureState.x0);
|
|
}
|
|
};
|
|
const _onPanResponderMoveRight = (e, gestureState) => {
|
|
const process =
|
|
(gestureState.x0 - 40 - thumbSize / 2 + gestureState.dx) / processWidth;
|
|
_changeProcess(process, "right");
|
|
};
|
|
const _changeProcess = (changeProcess, direction) => {
|
|
// 判断滑动开关
|
|
if (disabled) return;
|
|
if (changeProcess >= 0 && changeProcess <= 1) {
|
|
// 按步长比例变化刻度
|
|
const v = changeProcess * (upper_bound - lower_bound);
|
|
const newValue = Math.round(v / step) * step;
|
|
const newProcess = Math.round(newValue) / (upper_bound - lower_bound);
|
|
setStepNum(stepNum + 1);
|
|
if (process !== newProcess) {
|
|
if (direction == "left") {
|
|
if (newProcess < rightProcess) {
|
|
setLeftProcess(newProcess);
|
|
setStepNum((old) => old + 1);
|
|
onChange({
|
|
lower_bound: Math.round(
|
|
leftProcess * (upper_bound - lower_bound) + lower_bound
|
|
),
|
|
upper_bound: rightValue,
|
|
});
|
|
}
|
|
} else {
|
|
if (newProcess > leftProcess) {
|
|
// rightProcess.current = newProcess;
|
|
setRightProcess(newProcess);
|
|
setStepNum((old) => old - 1);
|
|
onChange({
|
|
lower_bound: leftValue,
|
|
upper_bound:
|
|
stepValues[
|
|
Math.round(
|
|
(newProcess * (upper_bound - lower_bound) + lower_bound) /
|
|
step
|
|
)
|
|
],
|
|
});
|
|
// setStepNum(stepNum - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return (
|
|
<View
|
|
// style={[
|
|
// styles.container,
|
|
// {
|
|
// height,
|
|
// width,
|
|
// },
|
|
// ]}
|
|
style={{
|
|
height: "upper_bound-content",
|
|
width,
|
|
// flex: 1,
|
|
flexDirection: "row",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
marginBottom: 36,
|
|
marginTop: 12,
|
|
}}
|
|
>
|
|
<View style={{ width: "100%", position: "relative" }}>
|
|
<View
|
|
style={{
|
|
backgroundColor: maximumTrackTintColor,
|
|
// flex: 1,
|
|
height: processHeight,
|
|
width: processWidth,
|
|
// marginRight: thumbSize / 2,
|
|
position: "absolute",
|
|
marginTop: -processHeight / 2,
|
|
left: thumbSize / 2,
|
|
zIndex: 1,
|
|
borderRadius: 50,
|
|
}}
|
|
/>
|
|
<View
|
|
style={{
|
|
backgroundColor: minimumTrackTintColor,
|
|
width: (rightProcess - leftProcess) * processWidth,
|
|
height: processHeight,
|
|
marginLeft: thumbSize / 2 + leftProcess * processWidth,
|
|
position: "absolute",
|
|
marginTop: -processHeight / 2,
|
|
left: 0,
|
|
zIndex: 10,
|
|
borderRadius: 50,
|
|
}}
|
|
/>
|
|
</View>
|
|
<View
|
|
transition={1000}
|
|
cachePolicy="disk"
|
|
// style={tailwind("w-full h-full rounded-lg overflow-hidden")}
|
|
style={{
|
|
width: thumbSize,
|
|
height: thumbSize,
|
|
borderRadius: 50,
|
|
position: "absolute",
|
|
left: leftProcess * processWidth,
|
|
marginTop: -processHeight / 2,
|
|
zIndex: 10,
|
|
backgroundColor: "#ff75c8",
|
|
borderColor: "#ffffff",
|
|
borderWidth: 2,
|
|
}}
|
|
{...leftWatcher.current?.panHandlers}
|
|
/>
|
|
<View
|
|
transition={1000}
|
|
cachePolicy="disk"
|
|
// style={tailwind("w-full h-full rounded-lg overflow-hidden")}
|
|
style={{
|
|
width: thumbSize,
|
|
height: thumbSize,
|
|
backgroundColor: "#fff",
|
|
borderRadius: 50,
|
|
position: "absolute",
|
|
left: rightProcess * processWidth,
|
|
zIndex: 10,
|
|
backgroundColor: "#ff75c8",
|
|
borderColor: "#ffffff",
|
|
borderWidth: 2,
|
|
}}
|
|
{...rightWatcher.current?.panHandlers}
|
|
></View>
|
|
<View
|
|
style={{
|
|
...tailwind("flex flex-row justify-between items-center"),
|
|
position: "absolute",
|
|
top: -46,
|
|
right: 12,
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
...tailwind("text-white text-lg"),
|
|
maxWidth: thumbSize * 2,
|
|
color: "#ff75c8",
|
|
}}
|
|
>
|
|
{Math.round(leftProcess * (upper_bound - lower_bound) + lower_bound)}
|
|
</Text>
|
|
<Text
|
|
style={{
|
|
...tailwind("text-lg"),
|
|
marginHorizontal: 4,
|
|
color: "#ff75c8",
|
|
}}
|
|
>
|
|
-
|
|
</Text>
|
|
<Text
|
|
style={{
|
|
...tailwind("text-white text-lg"),
|
|
// maxWidth: thumbSize * 2,
|
|
color: "#ff75c8",
|
|
}}
|
|
>
|
|
{hasInfinity && rightProcess == 1
|
|
? ">" + upper_bound
|
|
: stepValues[
|
|
Math.round(
|
|
(rightProcess * (upper_bound - lower_bound) + lower_bound) /
|
|
step
|
|
)
|
|
]}
|
|
</Text>
|
|
<Text
|
|
style={{
|
|
...tailwind("text-white text-lg"),
|
|
maxWidth: thumbSize * 2,
|
|
color: "#ff75c8",
|
|
}}
|
|
>
|
|
{unit}
|
|
</Text>
|
|
</View>
|
|
<Text
|
|
style={{
|
|
...tailwind("absolute text-white text-sm"),
|
|
left: 0,
|
|
top: 20,
|
|
minWidth: thumbSize,
|
|
maxWidth: thumbSize * 2,
|
|
color: "#ffffff80",
|
|
}}
|
|
>
|
|
{lower_bound}
|
|
</Text>
|
|
<Text
|
|
style={{
|
|
...tailwind("absolute text-white text-sm"),
|
|
left: processWidth,
|
|
top: 20,
|
|
minWidth: thumbSize,
|
|
maxWidth: thumbSize * 2,
|
|
color: "#ffffff80",
|
|
}}
|
|
>
|
|
{hasInfinity ? ">" + upper_bound : upper_bound}
|
|
</Text>
|
|
</View>
|
|
);
|
|
}
|