React Native开发

使用Animated.View和PanResponder写了个半

2021-12-10  本文已影响0人  182058734bf0

纯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的影响拖拽实时的进度我没计算,拖拽完成的进度我也没计算。

我刚开始的写的这个组件是希望能实现年龄段的选择,(就是能在一条线上,选出最大年龄,和最小年龄的功能)。不知道把头发干秃能不能做出来。

上一篇下一篇

猜你喜欢

热点阅读