tiefen_space_app/components/MySlider/index.jsx

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>
);
}