tiefen_space_app/components/MySlider/index.jsx

343 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { View, Text, PanResponder, Dimensions } from "react-native";
import React, { useState, useEffect, useRef } from "react";
import { useTailwind } from "tailwind-rn";
export default function MySlider({
lower_bound,
upper_bound,
step,
unit,
unitSite = "right",
width = Dimensions.get("window").width - 44,
onChange,
handleFunc = () => {},
disabled = false,
thumbSize = 25,
stepValues = [],
hasInfinity,
leftValue = lower_bound,
rightValue = stepValues[stepValues.length - 1],
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);
const currentLeftValue = useRef(leftValue);
const currentRightValue = useRef(rightValue);
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 =
(stepValues.indexOf(leftValue) * step - lower_bound) /
(upper_bound - lower_bound);
const currentRightProcess =
(stepValues.indexOf(rightValue) * step - lower_bound) /
(upper_bound - lower_bound);
setLeftProcess(currentLeftProcess);
setRightProcess(currentRightProcess);
currentLeftValue.current = leftValue;
currentRightValue.current = rightValue;
}, [leftValue, rightValue]);
// 左侧滑块事件
const _onPanResponderGrantLeft = () => {
handleFunc && handleFunc();
};
const _onPanResponderEndLeft = () => {
handleFunc && handleFunc();
};
const _onPanResponderMoveLeft = (e, gestureState) => {
const process =
(gestureState.x0 - thumbSize * 2 + gestureState.dx) / processWidth;
_changeProcess(process, "left");
};
// 右侧滑块事件
const _onPanResponderGrantRight = () => {
handleFunc && handleFunc();
};
const _onPanResponderEndRight = () => {
handleFunc && handleFunc();
};
const _onPanResponderMoveRight = (e, gestureState) => {
const process =
(gestureState.x0 - thumbSize / 2 + gestureState.dx) / processWidth;
_changeProcess(process, "right");
};
const _changeProcess = (changeProcess, direction) => {
// 判断滑动开关
if (disabled) return;
// 按步长比例变化刻度
changeProcess =
changeProcess > 1 ? 1 : changeProcess < 0 ? 0 : changeProcess;
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") {
const currentRightProcess =
(stepValues.indexOf(currentRightValue.current) * step - lower_bound) /
(upper_bound - lower_bound);
if (newProcess < currentRightProcess) {
const newLower =
stepValues[
Math.round(
(newProcess * (upper_bound - lower_bound) + lower_bound) / step
)
];
if (newLower <= currentRightValue.current - 3) {
setLeftProcess(newProcess);
setStepNum((old) => old + 1);
onChange({
lower_bound: newLower,
upper_bound: currentRightValue.current,
});
}
}
} else {
const currentLeftProcess =
(stepValues.indexOf(currentLeftValue.current) * step - lower_bound) /
(upper_bound - lower_bound);
if (newProcess > currentLeftProcess) {
const newUpper =
stepValues[
Math.round(
(newProcess * (upper_bound - lower_bound) + lower_bound) / step
)
];
if (newUpper >= currentLeftValue.current + 3) {
setRightProcess(newProcess);
setStepNum((old) => old - 1);
onChange({
lower_bound: currentLeftValue.current,
upper_bound: newUpper,
});
}
}
}
}
};
return (
<View
style={{
height: "upper_bound-content",
width,
// flex: 1,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
marginBottom: 36,
marginTop: 24,
}}
>
<View style={{ width: "100%", position: "relative" }}>
{/* 格子步数 */}
{hasInfinity && (
<View
style={{
...tailwind("flex flex-row justify-between items-center"),
position: "absolute",
top: -23,
flex: 1,
width: "100%",
padding: 17,
paddingRight: 20,
marginLeft: -12,
}}
>
{stepValues.map((item, index) => (
<View
key={index}
style={{
backgroundColor:
item >= leftValue && item <= rightValue
? minimumTrackTintColor
: maximumTrackTintColor,
width: thumbSize / 2,
height: thumbSize / 2,
borderRadius: 50,
}}
></View>
))}
</View>
)}
<View
style={{
backgroundColor: maximumTrackTintColor,
height: processHeight,
width: processWidth,
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={{
position: "absolute",
left: leftProcess * processWidth,
zIndex: 10,
width: thumbSize,
height: thumbSize,
borderRadius: 50,
backgroundColor: "#ff75c8",
borderColor: "#ffffff",
borderWidth: 2,
}}
{...leftWatcher.current?.panHandlers}
></View>
{/* 右侧控件 */}
<View
transition={1000}
cachePolicy="disk"
style={{
position: "absolute",
left: rightProcess * processWidth,
zIndex: 10,
width: thumbSize,
height: thumbSize,
backgroundColor: "#fff",
borderRadius: 50,
backgroundColor: "#ff75c8",
borderColor: "#ffffff",
borderWidth: 2,
}}
{...rightWatcher.current?.panHandlers}
></View>
<View
style={{
...tailwind("flex flex-row justify-between items-center"),
position: "absolute",
top: -54,
right: 24,
}}
>
{unitSite == "left" && (
<Text
style={{
...tailwind("text-white text-lg"),
maxWidth: thumbSize * 2,
color: "#ff75c8",
}}
>
{unit}
</Text>
)}
<Text
style={{
...tailwind("text-white text-lg"),
color: "#ff75c8",
}}
>
{hasInfinity && leftProcess == 1 ? ">" + upper_bound : leftValue}
</Text>
<Text
style={{
...tailwind("text-lg"),
marginHorizontal: 4,
color: "#ff75c8",
}}
>
</Text>
<Text
style={{
...tailwind("text-white text-lg"),
color: "#ff75c8",
}}
>
{hasInfinity && rightProcess >= 1 ? "∞" : rightValue}
</Text>
{unitSite == "right" && (
<Text
style={{
...tailwind("text-white text-lg"),
maxWidth: thumbSize * 2,
color: "#ff75c8",
}}
>
{unit}
</Text>
)}
</View>
<View
style={{
...tailwind(
"absolute text-white text-sm flex flex-row justify-between"
),
width: width - 22,
left: 0,
top: 20,
color: "#ffffff80",
}}
>
<Text
style={{
...tailwind(" text-white text-sm"),
minWidth: thumbSize,
maxWidth: thumbSize * 2,
color: "#ffffff80",
}}
>
{lower_bound}
</Text>
<Text
style={{
...tailwind(" text-white text-sm"),
minWidth: thumbSize,
color: "#ffffff80",
}}
>
{hasInfinity ? "∞" : upper_bound}
</Text>
</View>
</View>
);
}