在下面的简单滑块(打字稿)示例中,来自 react-native-gesture-handler 的 PanGestureHandler 只会在手势启动后设置。用户将需要移动手指。
这就是我想要实现的: Taps 还应该设置滑块值(包括点击和拖动)。这是一种常见的模式,例如在寻找视频文件或将音量设置为最大然后进行调整时。
我想我可以将它包装在 TapGestureHandler 中,但我正在寻找最优雅的方式来实现这一点,而无需太多样板。
// example extracted from https://www.npmjs.com/package/react-native-reanimated-slider
import React, { Component } from 'react';
import Animated from 'react-native-reanimated';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
const { Value, event, cond, eq, Extrapolate, interpolate } = Animated;
interface IProps {
minimumTrackTintColor: string;
maximumTrackTintColor: string;
cacheTrackTintColor: string;
value: number;
style: any;
cache;
onSlidingStart;
onSlidingComplete;
}
class Slider extends Component<IProps, {}> {
static defaultProps = {
minimumTrackTintColor: '#f3f',
maximumTrackTintColor: 'transparent',
cacheTrackTintColor: '#777',
};
private gestureState;
private x;
private width;
private clamped_x;
private onGestureEvent;
public constructor(props: IProps) {
super(props);
this.gestureState = new Value(State.UNDETERMINED);
this.x = new Value(0);
this.width = new Value(0);
this.clamped_x = cond(
eq(this.width, 0),
0,
interpolate(this.x, {
inputRange: [0, this.width],
outputRange: [0, this.width],
extrapolate: Extrapolate.CLAMP,
})
);
this.onGestureEvent = event([
{
nativeEvent: {
state: this.gestureState,
x: this.x,
},
},
]);
}
onLayout = ({ nativeEvent }) => {
this.width.setValue(nativeEvent.layout.width);
};
render() {
const { style, minimumTrackTintColor, maximumTrackTintColor } = this.props;
return (
<PanGestureHandler
onGestureEvent={this.onGestureEvent}
onHandlerStateChange={this.onGestureEvent}
>
<Animated.View
style={[
{
flex: 1,
height: 30,
overflow: 'visible',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#3330',
},
style,
]}
onLayout={this.onLayout}
>
<Animated.View
style={{
width: '100%',
height: 5,
borderRadius: 2,
overflow: 'hidden',
borderWidth: 1,
backgroundColor: maximumTrackTintColor,
}}
>
<Animated.View
style={{
backgroundColor: minimumTrackTintColor,
height: '100%',
maxWidth: '100%',
width: this.clamped_x,
position: 'absolute',
}}
/>
</Animated.View>
</Animated.View>
</PanGestureHandler>
);
}
}
export default Slider;
提前致谢!
编辑:这按预期工作,但有一个可见的渲染怪癖和一个小的延迟。
import React, { Component } from 'react';
import Animated from 'react-native-reanimated';
import { PanGestureHandler, TapGestureHandler, State } from 'react-native-gesture-handler';
const { Value, event, cond, eq, Extrapolate, interpolate } = Animated;
interface IProps {
minimumTrackTintColor?: string;
maximumTrackTintColor?: string;
cacheTrackTintColor?: string;
value: number;
style?: any;
onSlidingStart;
onSlidingComplete;
}
class Slider extends Component<IProps, {}> {
static defaultProps = {
minimumTrackTintColor: '#f3f',
maximumTrackTintColor: 'transparent',
cacheTrackTintColor: '#777',
};
private gestureState;
private x;
private width;
private clamped_x;
private onGestureEvent;
private onTapGesture;
public constructor(props: IProps) {
super(props);
this.gestureState = new Value(State.UNDETERMINED);
this.x = new Value(0);
this.width = new Value(0);
this.clamped_x = cond(
eq(this.width, 0),
0,
interpolate(this.x, {
inputRange: [0, this.width],
outputRange: [0, this.width],
extrapolate: Extrapolate.CLAMP,
})
);
this.onGestureEvent = event([
{
nativeEvent: {
state: this.gestureState,
x: this.x,
},
},
]);
this.onTapGesture = event([
{
nativeEvent: {
state: this.gestureState,
x: this.x,
},
},
]);
}
onLayout = ({ nativeEvent }) => {
this.width.setValue(nativeEvent.layout.width);
};
render() {
const { style, minimumTrackTintColor, maximumTrackTintColor } = this.props;
return (
<TapGestureHandler
onGestureEvent={this.onTapGesture}
onHandlerStateChange={this.onTapGesture}
>
<Animated.View>
<PanGestureHandler
onGestureEvent={this.onGestureEvent}
onHandlerStateChange={this.onGestureEvent}
>
<Animated.View
style={[
{
flex: 1,
height: 30,
overflow: 'visible',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#3330',
},
style,
]}
onLayout={this.onLayout}
>
<Animated.View
style={{
width: '100%',
height: 5,
borderRadius: 2,
overflow: 'hidden',
borderWidth: 1,
backgroundColor: maximumTrackTintColor,
}}
>
<Animated.View
style={{
backgroundColor: minimumTrackTintColor,
height: '100%',
maxWidth: '100%',
width: this.clamped_x,
position: 'absolute',
}}
/>
</Animated.View>
</Animated.View>
</PanGestureHandler>
</Animated.View>
</TapGestureHandler>
);
}
}
export default Slider;