React Native: Animated Scroll Header 구현기

poburi FE·2020년 10월 29일
0

THL

목록 보기
9/10

애니메이션을 만들기위한 핵심 워크 플로:
1. Animated.Value를 만들고
2. 애니메이션 구성 요소의 하나 이상의 스타일 속성에 연결한 다음
3. Animated.timing()을 사용해 애니메이션을 업데이트한다.

inputRange, outputRange...?

세로로 스크롤하는 거로 예를 들자면 inputRange는 스크롤하기 시작했을때
다시 원상태로 돌아오는 것이 끝나갈때쯤이 outputRange라고 생각

스크롤 이벤트 생성하기...

onScroll={Animated.event([
	{
    	nativeEvent: {
        	contentOffset: {
            	y: scrollY
            }
        }
    }
])}

헤더 구현

ScreenWidth = Dimensions.get('window').width;

<Animated.View
	style={
    	flexDirection: 'row',
        justifyContent: 'center',
        paddingHorizontal: screenWidth * 0.05,
        width: screenWidth,
        alignItems: 'flex-end',
        height: scrollOffset.interpolate({
        	inputRange: [0, 200],
            ouputRange: [120, 64],
            extrapolate: 'clamp',
        })
    }
>

왼쪽 정렬 상태를 만들고 폰트의 사이즈를 변화시켜주고 싶다면 꼼수를 부려야함.
나는 그것을 onLayout으로 구현하였다.

onLayout은 렌더링 후 화면에서 뷰의 정확한 크기를 알려주는 편리한 콜백을 제공해줌.

const [titleWidth, setTitleWidth] = useState(0);

onLayout = (e) => {
	setTitleWidth(e.nativeEvent.layout.width);
}

헤더 제목 텍스트가 렌더링될 때 너비를 저장하면 헤더에서 바로 오른쪽에 보이지 않는 뷰를 추가해 왼쪽 정렬로 밀어넣는 것이다.

헤더의 넓이 = 화면 너비
왼쪽과 오른쪽에 모두 5%의 패딩이 있었다.
따라서 제목이 렌더링되는 공간의 너비는 화면 너비의 90%가 된다.
따라서 보이지 않는 뷰의 넓이는 screenWidth * 0.9 - titleWidth가 된다.

<Animated.Text 
  onLayout = {e => { 
    const titleWidth = e.nativeEvent.layout.width; 
    this.setState ({titleWidth}); 
  }} 
  style = {{ 
    fontWeight : 'bold', 
    fontSize : 26, 
  }} 
>
I'm Header
</Animated.Text> 
<Animated.View 
  style = {{ 
    width : screenWidth * 0.9-this.state.titleWidth, 
  }} 
/>

이렇게 해서 초기 위치 값을 왼쪽으로 정렬해줄 수 있다.

보이지 않는 뷰의 역할...

애니메이션이 끝날 때 보이지 않는 뷰의 너비를 초기에 설정한 넓이에서 0이 된다면 텍스트는 중앙에 배치되게 된다.

<Animated.Text 
  onLayout = {e => { 
    const titleWidth = e.nativeEvent.layout.width; 
    this.setState ({titleWidth}); 
  }} 
  style = {{ 
    fontWeight : 'bold', 
    fontSize : 26, 
  }} 
>
I'm Header
</Animated.Text> 
<Animated.View 
  style = {{ 
    width : scrollOffset.interpolate({
    	inputRange: [0, 200],
        outputRange: [screenWidth * 0.9-this.state.titleWidth,0],
        extrapolate: 'clamp' 
    }), 
    
  }} 
/>
profile
FE 개발자 poburi

0개의 댓글