Poylib
기록형 프론트엔드
Poylib
전체 방문자
오늘
어제
  • 분류 전체보기 (91)
    • Programing (38)
      • Javascript (17)
      • Typescript (1)
      • React (9)
      • React-Native (6)
      • Git (4)
      • Next (1)
    • Study (36)
      • Algorithm (35)
      • Etc. (1)
    • Record (17)
      • Memoirs (12)
      • Group (5)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 코칭스터디
  • 코딩테스트
  • 리액트
  • Object
  • javascript
  • vite
  • 백준
  • react
  • 프로그래머스
  • typescript
  • 회고
  • 알고리즘
  • 기초
  • ReactNative
  • Error
  • 자바스크립트
  • react-native
  • Git

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Poylib

기록형 프론트엔드

[RN] 플로팅 버튼 아래로 스크롤 할 때만 나오게 구현(feat. reanimated)
Programing/React-Native

[RN] 플로팅 버튼 아래로 스크롤 할 때만 나오게 구현(feat. reanimated)

2023. 7. 5. 23:46

How to

간단하게 Y값 조절로 버튼을 화면 아래 숨겨뒀다가 아래로 스크롤할 때만 나오게 하면 된다. 화면 상단에 헤더, 카테고리 버튼 등이 이미 있을 때 하단 버튼까지 만들어두기엔 스크린이 좁게 느껴져서 유저가 스크롤을 올릴 때는 버튼을 숨기고 싶었다.

<Animated.ScrollView scrollEventThrottle={16} onScroll={scrollHandler}>
  <View style={{ backgroundColor: '#a7A5E3', height: 700 }} />
  <View style={{ backgroundColor: '#a3e3e3', height: 700 }} />
  <View style={{ backgroundColor: '#6979BB', height: 700 }} />
</Animated.ScrollView>
<Animated.View style={[styles.button, actionBarStyle]}>
  <Text style={styles.buttonText}>자세히 보기</Text>
</Animated.View>

reanimated를 사용해서 ScrollView와 하단 버튼을 만들었다. '자세히 보기' 버튼의 경우 translateY값을 한참 높게 줘서 스크린 하단을 넘겨버리면 버튼을 숨길 수 있다. 스크롤을 내렸다는 게 감지되면 translateY의 값을 0으로 줘서 제위치로 돌아오게 하면 버튼이 아래에서 위로 올라오게 될 것이다.

  const translateY = useSharedValue(1000);

  const actionBarStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateY: withTiming(translateY.value, {
            duration: 500,
            easing: Easing.inOut(Easing.ease),
          }),
        },
      ],
    };
  });

ScrollHandler

  const lastContentOffset = useSharedValue(0);
  const isScrolling = useSharedValue(false);
  const translateY = useSharedValue(1000);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: event => {
      if (
        lastContentOffset.value > event.contentOffset.y &&
        isScrolling.value
      ) {
        translateY.value = 1000;
        // console.log('scrolling up');
      } else if (
        lastContentOffset.value < event.contentOffset.y &&
        isScrolling.value
      ) {
        translateY.value = 0;
        // console.log('scrolling down');
      }

      lastContentOffset.value = event.contentOffset.y;
    },
    onBeginDrag: e => {
      isScrolling.value = true;
    },
    onEndDrag: e => {
      isScrolling.value = false;
    },
  });

 

 

isScrolling 값으로 유저가 스크롤 중인지, 끝났는지 확인하고 스크롤이 끝났다면 스크롤 전의 y값과 비교해서 스크롤을 올렸는지 내렸는지 확인할 수 있다. 즉 스크롤이 시작될 때 유저가 보고있는 스크린의 y값과 스크롤 후의 y값을 비교한다. 스크롤을 내렸다면  translateY 값을 0으로 돌려 스크린에 버튼을 노출시켰다.

 

조건을 조금 응용하자면 특정 지점을 넘었을 때만 스크롤을 아래로 내릴 경우 버튼이 노출되게 할 수 있다.

   onScroll: event => {
      if (
        lastContentOffset.value > event.contentOffset.y &&
        isScrolling.value
      ) {
        translateY.value = 1000;
        // console.log('scrolling up');
      } else if (
        lastContentOffset.value < event.contentOffset.y &&
        isScrolling.value &&
        event.contentOffset.y > 700
      ) {
        translateY.value = 0;
        // console.log('scrolling down');
      }

      lastContentOffset.value = event.contentOffset.y;
    },

스크롤을 내렸다고 처음부터 버튼이 노출될 필요는 없다면 이런식의 조건을 덧붙이는 것도 방법일 것이다.

 

code

import Animated, {
  Easing,
  useAnimatedScrollHandler,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';

const ScrollDownEvent = () => {
  const lastContentOffset = useSharedValue(0);
  const isScrolling = useSharedValue(false);
  const translateY = useSharedValue(1000);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: event => {
      if (
        lastContentOffset.value > event.contentOffset.y &&
        isScrolling.value
      ) {
        translateY.value = 1000;
        // console.log('scrolling up');
      } else if (
        lastContentOffset.value < event.contentOffset.y &&
        isScrolling.value &&
        event.contentOffset.y > 700
      ) {
        translateY.value = 0;
        // console.log('scrolling down');
      }

      lastContentOffset.value = event.contentOffset.y;
    },
    onBeginDrag: e => {
      isScrolling.value = true;
    },
    onEndDrag: e => {
      isScrolling.value = false;
    },
  });

  const actionBarStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateY: withTiming(translateY.value, {
            duration: 500,
            easing: Easing.inOut(Easing.ease),
          }),
        },
      ],
    };
  });

  return (
    <>
      <Animated.ScrollView scrollEventThrottle={16} onScroll={scrollHandler}>
        <View style={{ backgroundColor: '#a7A5E3', height: 700 }} />
        <View style={{ backgroundColor: '#a3e3e3', height: 700 }} />
        <View style={{ backgroundColor: '#6979BB', height: 700 }} />
      </Animated.ScrollView>
      <Animated.View style={[styles.button, actionBarStyle]}>
        <Text style={styles.buttonText}>자세히 보기</Text>
      </Animated.View>
    </>
  );
};

const styles = StyleSheet.create({
  container: {
    height: 700,
  },
  button: {
    position: 'absolute',
    alignItems: 'center',
    justifyContent: 'center',
    bottom: 45,
    left: 24,
    right: 24,
    padding: 24,
    borderRadius: 100,
    backgroundColor: '#fff',
  },
  buttonText: {
    fontSize: 18,
  },
});

export default ScrollDownEvent;
저작자표시 비영리 변경금지 (새창열림)

'Programing > React-Native' 카테고리의 다른 글

[RN] 인생이 지루하다면 react-native upgrade (0.66.3 -> 0.72.5)  (1) 2023.11.15
[RN] Node 업그레이드 후 빌드 오류 (error:0308010C:digital)  (0) 2023.09.11
[RN] reanimated로 flipCard 만들기  (2) 2023.04.20
[RN] zsh에서 gradle 에 맞는 Java 버전변경 ( version 62 )  (0) 2023.01.27
[RN] android 빌드 실패 No connected devices  (0) 2023.01.22
    'Programing/React-Native' 카테고리의 다른 글
    • [RN] 인생이 지루하다면 react-native upgrade (0.66.3 -> 0.72.5)
    • [RN] Node 업그레이드 후 빌드 오류 (error:0308010C:digital)
    • [RN] reanimated로 flipCard 만들기
    • [RN] zsh에서 gradle 에 맞는 Java 버전변경 ( version 62 )
    Poylib
    Poylib
    모시깽 기록

    티스토리툴바