Last active
August 1, 2023 04:26
-
-
Save dohooo/bfda3d320201eb54b42c04b681c26a89 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, type FC } from "react"; | |
import { Button, Dimensions, ScrollView, Text, View } from "react-native"; | |
import type { SharedValue } from "react-native-reanimated"; | |
import { Easing, Extrapolate, interpolate, useDerivedValue, useSharedValue, withDecay, withDelay, withRepeat, withTiming } from "react-native-reanimated"; | |
import { SafeAreaView } from "react-native-safe-area-context"; | |
import { Blur, Canvas, DisplacementMap, Fill, FractalNoise, Group, LinearGradient, Rect, RoundedRect, Shadow, Turbulence, Vertices, vec } from "@shopify/react-native-skia"; | |
const { width } = Dimensions.get("window"); | |
const posCount = 12; | |
const posGap = width / (posCount - 2); | |
const posArr = Array.from({ length: posCount }).map((_, i) => [i * posGap, 0]); | |
const height = width / 1.58; | |
const lineWidth = 20; | |
const AnimatedLine: FC<{ | |
index: number | |
x: number | |
y: number | |
animVal: SharedValue<number> | |
}> = ({ index, x, y, animVal }) => { | |
const animatedGap = 50 / posCount; | |
const startInput = animatedGap * index; | |
const endInput = animatedGap * (index + 1); | |
const animatedX = useDerivedValue(() => { | |
return interpolate( | |
animVal.value, | |
[-100, -80, -50, -20, 0], | |
[x + 50, x + 50, x, x + 50, x + 50], | |
); | |
}, [x, animVal]); | |
const animatedOpacity = useDerivedValue(() => { | |
const animatedGap = 50 / posCount * 2; | |
const startInput = animatedGap * index; | |
const endInput = animatedGap * (index + 1); | |
return interpolate( | |
animVal.value, | |
[-endInput, -startInput, -startInput, -endInput], | |
[0.2, 1, 1, 0.2], | |
Extrapolate.CLAMP, | |
); | |
}, [x, animVal]); | |
const animatedWidth = useDerivedValue(() => { | |
const width = lineWidth + (posCount - index) - index * 1; | |
return interpolate( | |
animVal.value, | |
[-endInput, -startInput, -startInput, -endInput], | |
[width * 0.9, width, width, width * 0.9], | |
Extrapolate.CLAMP, | |
); | |
}, [x, animVal, index]); | |
return ( | |
<Rect | |
x={animatedX} | |
y={y - (width / 2)} | |
width={animatedWidth} | |
height={width * 2} | |
opacity={animatedOpacity} | |
transform={[{ rotate: Math.PI / 12 + 1.2 * index / 40 }]} | |
> | |
<LinearGradient | |
start={vec(0, width)} | |
end={vec(width, 0)} | |
positions={[0, 0.5, 0.65, 0.7, 0.9, 1]} | |
colors={["#000", "rgba(15,104,82,1)", "rgba(15,104,82,1)", "#39738046", "#193355", "#193355"]} | |
/> | |
</Rect> | |
); | |
}; | |
const AnimatedMask: FC<{ | |
animVal: SharedValue<number> | |
}> = ({ animVal }) => { | |
const animatedBlur = useDerivedValue(() => { | |
return interpolate( | |
animVal.value, | |
[-100, -50, 0], | |
[5, 3, 5], | |
Extrapolate.CLAMP, | |
); | |
}, []); | |
return ( | |
<Blur blur={animatedBlur} mode={"decal"}/> | |
); | |
}; | |
const AnimationExample = () => { | |
const animVal = useSharedValue(0); | |
useEffect(() => { | |
animVal.value = withRepeat( | |
withTiming( | |
animVal.value > -50 ? -100 : 0, | |
{ duration: 10 * 1000, easing: Easing.linear }, | |
), 0, true); | |
}, []); | |
return ( | |
<ScrollView style={{ backgroundColor: "black", flex: 1 }}> | |
<Canvas style={{ width, height }}> | |
<Group> | |
<Rect x={0} y={0} width={width} height={width}> | |
<LinearGradient | |
start={vec(width, 0)} | |
end={vec(0, width)} | |
positions={[0, 0.4, 0.5, 0.9, 1]} | |
colors={["#193355", "#193355", "#397380", "#0F6852"]} | |
/> | |
</Rect> | |
{ | |
posArr.map(([x, y], i) => ( | |
<AnimatedLine | |
key={i} | |
x={x} | |
index={i} | |
animVal={animVal} | |
y={y - (width / 2)} | |
/> | |
)) | |
} | |
<Vertices | |
vertices={[vec(width * 1.1, height * 0.15), vec(width * 1.1, height * 1.1), vec(-width * 0.1, height * 1.1)]} | |
colors={["#000000b2", "#000", "#000000b2"]} | |
> | |
<Shadow dx={-20} dy={-20} blur={30} color="#000" /> | |
<Blur blur={10} /> | |
</Vertices> | |
<Rect | |
x={0} | |
y={height * 0.6} | |
width={width * 0.25} | |
height={height * 0.4} | |
transform={[{ rotate: Math.PI / 12 }]} | |
color={"rgba(15,104,82,1)"} | |
> | |
<Shadow dx={-10} dy={-10} blur={20} color="#0000007d" /> | |
<Blur blur={20} /> | |
</Rect> | |
<AnimatedMask animVal={animVal}/> | |
</Group> | |
<Rect x={0} y={0} width={width} height={width}> | |
<Turbulence | |
freqX={2.3} | |
freqY={2.3} | |
octaves={1} | |
/> | |
</Rect> | |
<Rect | |
x={-20} | |
y={height - 20} | |
width={width} | |
height={20} | |
color={"black"} | |
> | |
<Blur blur={20} /> | |
</Rect> | |
</Canvas> | |
<Text style={{ alignSelf: "center", marginTop: -28, paddingHorizontal: 12, color: "white", fontSize: 24, fontWeight: "700" }}>VA-11 Hall-A- 在赛博酒吧里寻求生机</Text> | |
</ScrollView> | |
); | |
}; | |
export default AnimationExample; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment