스크롤 이벤트에 따른 이미지변화를 애니메이션으로 나타나는 예제를 만들어볼라한다.
우선 React Native에 animation을 주기위해선, Animated를 import해야한다.
import{ Animated} from 'react-native'
이렇게 해주면 애니메이션에대한 준비는 끝났다.
App.js
import React, {useRef} from 'react';
import {
StyleSheet,
Text,
View,
ScrollView,
SafeAreaView,
Animated,
Image,
Dimensions,
} from 'react-native';
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const MAINIMG = windowHeight / 3.3;
const App = ()=> {
return(
<SafeAreaView style={styles.safeView}>
<ScrollView style={styles.container}>
<View style={styles.imgWrap}>
<Image style={styles.img} source={require('../assets/rn.png')}/>
</View>
<View style={styles.textWrap}>
<Text style={styles.dummyText}>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type
and scrambled it to make a type specimen book. It has survived not
only five centuries, but also the leap into electronic typesetting,
remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing software like Aldus
PageMaker including versions of Lorem Ipsum. Lorem Ipsum is simply
dummy text of the printing and typesetting industry. Lorem Ipsum has
been the industry's standard dummy text ever since the 1500s, when
an unknown printer took a galley of type and scrambled it to make a
type specimen book. It has survived not only five centuries, but
also the leap into electronic typesetting, remaining essentially
unchanged. It was popularised in the 1960s with the release of
Letraset sheets containing Lorem Ipsum passages, and more recently
with desktop publishing software like Aldus PageMaker including
versions of Lorem Ipsum. Lorem Ipsum is simply dummy text of the
printing and typesetting industry. Lorem Ipsum has been the
industry's standard dummy text ever since the 1500s, when an unknown
printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but also the
leap into electronic typesetting, remaining essentially unchanged.
It was popularised in the 1960s with the release of Letraset sheets
containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem
Ipsum. Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry's standard
dummy text ever since the 1500s, when an unknown printer took a
galley of type and scrambled it to make a type specimen book. It has
survived not only five centuries, but also the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in
the 1960s with the release of Letraset sheets containing Lorem Ipsum
passages, and more recently with desktop publishing software like
Aldus PageMaker including versions of Lorem Ipsum.
</Text>
</View>
</ScrollView>
</SafeAreaView>
)}
const styles = StyleSheet.create({
safeView: {
flex: 1,
backgroundColor: '#1C1C1E',
},
container: {
flex: 1,
width: '100%',
backgroundColor: '#1C1C1E',
paddingBottom: '15%',
},
imgWrap: {
alignItems: 'center',
width: windowWidth,
height: windowHeight / 3.3,
},
img: {
width: windowWidth * 2,
height: MAINIMG,
resizeMode: 'center',
},
textWrap: {
backgroundColor: 'white',
padding: 20,
},
dummyText: {
lineHeight: 20,
},
});
export default App;
}
위의 이미지와 같은 이미지와 더미텍스트가 존재하는 예제를 만들었다.
React Native에서는 animation을 사용할수있는 컴포넌트가 제한적이다.
View, Text, Image, ScrollView, FlatList and SectionList
만약, 이외의 컴포넌트를 사용할경우에는 Animated.createAnimatedComponent()를 이용하여 만들면된다.
이글에서는 위에 나온 컴포넌트로 애니메이션을 이용해보자.
그리고 애니메이션은 타입이 존재하는데,
Timing타입이 가장 기본적인 접근방식이다.
애니메이션 초기값 설정
애니메이션을 사용하기 위하여 먼저 초기값을 정의해야한다.
설정된 초기값을 useRef를 이용하여 만든다.
import React, {useRef} from 'react';
...
const App = () =>{
const scrollA = useRef(new Animated.Value(0)).current;
...
그다음은 컴포넌트로 Animate를 렌더링해야한다.
<Animated.ScrollView>
</Animated.ScrollView>
이벤트 발생
스크롤 이벤트가 발생할때 애니메이션이 작동하기위해, ScrollView에 onScroll 이벤트를 걸어준다.
여기서 useNativeDriver:true 는 Animated 모듈은 React Native의 JavaScript 측에서 애니메이션을 수행하고 단일 스레드를 공유한다. 그래서 애니메이션이 부드럽게 작동하지 않을 수 있기에 useNativeDriver:true 옵션을 사용하여 애니메이션을 부드럽게 작동시킨다1.
수직으로 스크롤이벤트가 일어났을때 애니메이션함수가 호출된다.
<Animated.ScrollView
style={styles.container}
onScroll={Animated.event([{nativeEvent:{contentOffset:{y:scrollA}}}],
{useNativeDriver:true})}
>
</Animated.ScrollView>
interpolate
interpolate() 함수를 통해 정의값의 범위를 지정할수있다.
- inputRange : 애니메이션 값의 범위
- outRage : interpolate된 값이 inputRage에 맵핑된 결과 (string값도가능)
value.interpolate({
inputRange: [0, 1],
outputRange: ['0px', '100px'],
});
** 애니메이션값이 0 에서 1로 변할때 0px에서 100px로 변한다
그후 style에서 scrollA를 props로 받아 이벤트를 처리한다
const styles = StyleSheet.create({
...
img: scrollA => ({
width: windowWidth * 2,
height: MAINIMG,
resizeMode: 'center',
transform: [
{
translateY: scrollA.interpolate({
inputRange: [-MAINIMG, 0, MAINIMG, MAINIMG + 1],
outputRange: [-MAINIMG / 2, 0, MAINIMG * 0.75, MAINIMG * 0.75],
}),
},
{
scale: scrollA.interpolate({
inputRange: [-MAINIMG, 0, MAINIMG, MAINIMG + 1],
outputRange: [2, 1, 0.5, 0.5],
}),
},
],
}),
textWrap: {
backgroundColor: 'white',
padding: 20,
},
dummyText: {
lineHeight: 20,
},
)}
scale: scrollA.interpolate({
inputRange: [-MAINIMG, 0, MAINIMG, MAINIMG + 1],
outputRange: [2, 1, 0.5, 0.5],
}),
스크롤을 아래로 내렸을때, 이미지 크기는 2, 현위치일때 1, 스크롤을 올렸을때 이미지 스케일이 반값이된다.
import React, {useRef} from 'react';
import {
StyleSheet,
Text,
TouchableOpacity,
View,
ScrollView,
SafeAreaView,
Animated,
Image,
Dimensions,
} from 'react-native';
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const MAINIMG = windowHeight / 3.3;
const App = ({
counter,
handleAddCounter,
handleRemoveCounter,
handleIncrement,
handleDecrement,
}) => {
// scroll Animation
const scrollA = useRef(new Animated.Value(0)).current;
return (
<SafeAreaView style={styles.safeView}>
<Animated.ScrollView
style={styles.container}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: scrollA}}}],
{useNativeDriver: true},
)}
scrollEventThrottle={16}>
<View style={styles.imgWrap}>
<Animated.Image
style={styles.img(scrollA)}
source={require('../assets/rn.png')}
/>
</View>
<View style={styles.textWrap}>
<Text style={styles.dummyText}>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type
and scrambled it to make a type specimen book. It has survived not
only five centuries, but also the leap into electronic typesetting,
remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing software like Aldus
PageMaker including versions of Lorem Ipsum. Lorem Ipsum is simply
dummy text of the printing and typesetting industry. Lorem Ipsum has
been the industry's standard dummy text ever since the 1500s, when
an unknown printer took a galley of type and scrambled it to make a
type specimen book. It has survived not only five centuries, but
also the leap into electronic typesetting, remaining essentially
unchanged. It was popularised in the 1960s with the release of
Letraset sheets containing Lorem Ipsum passages, and more recently
with desktop publishing software like Aldus PageMaker including
versions of Lorem Ipsum. Lorem Ipsum is simply dummy text of the
printing and typesetting industry. Lorem Ipsum has been the
industry's standard dummy text ever since the 1500s, when an unknown
printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but also the
leap into electronic typesetting, remaining essentially unchanged.
It was popularised in the 1960s with the release of Letraset sheets
containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem
Ipsum. Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry's standard
dummy text ever since the 1500s, when an unknown printer took a
galley of type and scrambled it to make a type specimen book. It has
survived not only five centuries, but also the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in
the 1960s with the release of Letraset sheets containing Lorem Ipsum
passages, and more recently with desktop publishing software like
Aldus PageMaker including versions of Lorem Ipsum.
</Text>
</View>
</Animated.ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeView: {
flex: 1,
backgroundColor: '#1C1C1E',
},
container: {
flex: 1,
width: '100%',
backgroundColor: '#1C1C1E',
// paddingTop: '15%',
paddingBottom: '15%',
}
imgWrap: {
alignItems: 'center',
width: windowWidth,
height: windowHeight / 3.3,
},
img: scrollA => ({
width: windowWidth * 2,
height: MAINIMG,
resizeMode: 'center',
transform: [
{
translateY: scrollA.interpolate({
inputRange: [-MAINIMG, 0, MAINIMG, MAINIMG + 1],
outputRange: [-MAINIMG / 2, 0, MAINIMG * 0.75, MAINIMG * 0.75],
}),
},
{
scale: scrollA.interpolate({
inputRange: [-MAINIMG, 0, MAINIMG, MAINIMG + 1],
outputRange: [2, 1, 0.5, 0.5],
}),
},
],
}),
textWrap: {
backgroundColor: 'white',
padding: 20,
},
dummyText: {
lineHeight: 20,
},
});
export default App;