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 |