React Native) 캐러셀 만들기 (feat. ScrollView)

2ast·2022년 10월 6일
0
post-custom-banner

앱을 만들다보면 가로로 컨텐츠를 스크롤하는 캐러셀이 필요할 때가 있다. 그럴 때 외부 라이브러리를 사용하는 것도 방법이지만, 복잡한 애니메이션을 필요로 하는게 아닌 이상 ScrollView 만으로 충분히 구현할 수도 있다.

일단 결과물 부터 보고 시작

//ScrollViewCarousel.tsx
import styled from '@emotion/native';
import React, {useState} from 'react';
import {ScrollView} from 'react-native';


const CarouselContainer = styled.View`
  flex: 1;
`;
const Row = styled.View`
  flex-direction: row;
`;
const CarouselItemContainer = styled.View`
  width: ${(props: {width: number}) => props.width}px;
  height: 100%;
  padding: 20px;
`;
const CarouselItem = styled.View`
  flex: 1;
  background-color: ${(props: {color: string}) => props.color};
`;

const ScrollViewCarousel = () => {
  const data = ['tomato', 'skyblue', 'green', 'beige', 'yellow'];
  const [itemWidth, setItemWidth] = useState(0);

  return (
    <CarouselContainer style={{flex: 1}}>
      <ScrollView
        style={{flex: 1}}
        horizontal
        pagingEnabled
        contentContainerStyle={{width: `${100 * data.length}%`}}
        scrollEventThrottle={200}
        decelerationRate="fast"
        onContentSizeChange={w => setItemWidth(w / data.length)}
        showsHorizontalScrollIndicator={false}>
        <Row>
          {data.map((item: string) => {
            return (
              <CarouselItemContainer key={item} width={itemWidth}>
                <CarouselItem color={item} />
              </CarouselItemContainer>
            );
          })}
        </Row>
      </ScrollView>
    </CarouselContainer>
  );
};

export default ScrollViewCarousel;

---------------------------------------
//App.tsx
import React from 'react';
import ScrollViewCarousel from './src/components/ScrollViewCarousel';
import styled from '@emotion/native';


const AppBackground = styled.View`
  justify-content: center;
  align-items: center;
  flex: 1;
  background-color: black;
`;

const CarouselBox = styled.View`
  width: 80%;
  height: 60%;
  border-radius: 10px;
  background-color: white;
  overflow: hidden;
`;

const App = () => {
  return (
    <AppBackground>
      <CarouselBox>
        <ScrollViewCarousel />
      </CarouselBox>
    </AppBackground>
  );
};

export default App;

설명하자면 이렇습니다.

 <ScrollView
        style={{flex: 1}}
        horizontal
        pagingEnabled
        contentContainerStyle={{width: `${100 * data.length}%`}}
        scrollEventThrottle={200}
        decelerationRate="fast"
        onContentSizeChange={w => setItemWidth(w / data.length)}
        showsHorizontalScrollIndicator={false}>
      </ScrollView>

이 코드의 가장 핵심은 당연하게도 ScrollView에 있다. 각각 하나씩 설명하자면, 먼저 ScrollView 또한 하나의 View 이므로, flex:1을 주어 CarouselContainer를 가득 채워주었고, contentContainerStyle 속성을 통해 contentContainer의 width를 CarouselContainer의 width* data의 길이만큼 주었다. 그리고 onContentSizeChange를 사용해 퍼센트로 계산된 contentContainer의 width를 정확한 px값으로 가져왔다. 이제 이렇게 받아온 width 값을 다시 캐러셀에 보여주고 싶은 data의 갯수만큼 나눠서 각 아이템의 width가 CarouselContainer에 가득 차도록 width 값을 얻어낸 것이다. (이부분은 조금 복잡할 수 있으므로 여러번 코드를 읽어볼 필요가 있다.)

그 외에 다른 속성들로는 가로 스크롤을 위한 horizontal, 스크롤 할때마다 자석처럼 각 아이템이 중앙에 올 수 있도록 해주는 pagingEnabled, 최적화에 사용되는 scrollEventThrottle, 터치를 뗀 후 스크롤이 멈추는 속도를 결정하는 decelerationRate, 스크롤바를 안보이게 설정할 수 있는 showHorizontalScrollIndicator가 있다.

간단한듯 복잡한데 간단한 캐러셀

이처럼 ScrollView의 기본 속성만으로 빠르게 캐러셀을 만들어볼 수 있었다. (스타일 코드가 캐러셀 구현 코드보다 더 긴 것 같다.) 캐러셀 각 아이템의 너비를 받아와서 계산하는 로직이 조금 복잡할 수 있지만, 이부분은 직접 한두번 구현해보면 어떤 느낌인지 알 수 있을 거라고 생각한다.

참고 링크: https://rossbulat.medium.com/react-native-carousels-with-horizontal-scroll-views-60b0587a670c

profile
React-Native 개발블로그
post-custom-banner

0개의 댓글