스프링처럼 늘어났다 줄어드는 바텀시트 만들기

dahee park·2022년 11월 6일
0
post-thumbnail

처음에 바텀시트가 필요해서 react-spring-bottom-sheet를 사용했는데 안드로이드인가 ios에서 생긴 문제가 해결될 기미가 보이지 않아서 급하게 직접 만들었다. 무슨 문제인지는 기억나지 않는다... 다음부터는 문제를 해결하지 못하더라도 발생한 문제는 기록을 해야 겠다.

react-spring-bottom-sheet처럼 올리면 올리는 만큼 끝부분이 늘어났다가 떼면 제자리로 돌아오고 내리면 내리는 만큼 내려가는 바텀시트를 만들고 싶었다.

터치 이벤트 사용하기

바텀시트의 핸들부분을 터치한 다음 그대로 올리고 내리는 동작을 감지해야했기 때문에 바텀시트의 핸들부분에 손가락을 핸들에 두면서 터치가 시작될 때와 손가락을 떼면서 터치가 끝날 때, 손가락을 핸들에 둔 상태에서 움직일 때 이벤트 핸들러를 설정해주었다.

const [diff, setDiff] = useState(0);
let prevYPos = 0;
let currentYPos = 0;
/* 바텀 시트 중 핸들 부분 */
<div
	css={headerStyle}
	onTouchStart={(event) => {
		prevYPos = event.touches[0].clientY;
	}}
	onTouchMove={(event) => {
		currentYPos = event.touches[0].clientY;
		setDiff((prev) => prev + prevYPos - currentYPos);
		prevYPos = currentYPos;
	}}
	onTouchEnd={() => {
		if (diff < -40) closeBottomSheet();
		setDiff(0);
	}}
>
	<div css={handleStyle} />
</div>

터치가 시작될 때, 최초 터치를 한 지점의 y좌표를 prevYPos에 담아준다.
터치가 움직이면, 이동한 지점의 y좌표를 currentYPos에 담아준다. diff에는 diff에 이미 담겨있는 값에 움직인 거리인 이전 좌표와 현재 좌표의 차이를 더해준다. 이전 y좌표 값인 prevYPos는 현재 y좌표 값인 currentYPos로 갱신해준다.
터치가 끝나면 바텀시트를 닫는데 이때 diff가 -40이면 닫는다. 핸들을 최초로 터치한 지점으로부터 40만큼 아래로 내려가면 닫게 만들기 위해 추가한 조건이다. 마지막으로 diff을 0으로 다시 초기화해준다.

padding과 margin을 이용하기

<div css={moveBottomSheet(diff)}>
	<div /> // 핸들
    {props.children} // 바텀시트 안에 들어갈 컨텐츠
<div>

const moveBottomSheet = (diff) => {
	if (diff === 0) return;
    if (diff > 0)
    	return css`
        	padding-bottom: ${diff}px;
        `;
    else
    	return css`
        	margin-bottom:: ${diff}px;
        `;
}

(emotion을 사용하여 css 스타일링을 하였다.)

바텀시트 전체를 감싸고 있는 div에 변화하는 diff 값 만큼 padding-bottom과 margin-bottom에 값을 넣어준다.
최초 터치 지점으로부터 터치가 위로 올라가서 diff 값이 양수가 나오면 padding-bottom에 diff만큼 값을 넣어주어 올린만큼 아래 빈 공간이 생기도록 하고
최초 터치 지점으로부터 터치가 아래로 내려가서 diff 값이 음수가 나오면 margin-bottom에 diff만큼 값을 넣어주어 내린만큼 바텀시트가 내려가도록 해주었다.

결과

터치 이벤트는 처음 다뤄봐서 재미있었다. react-spring-bottom-sheet만큼 유려하지는 않지만... 그래도 원하던대로 동작을 하니 다행이다. react-spring-bottom-sheet에서는 터치가 움직일 때마다 transform: translateY(); 값이 변하던데 어떻게 구현했는지 나중에 자세히 알아보고 싶다. 마지막에 바텀시트가 닫힐 때 내려가는 모션을 끝까지 유지하면서 닫히도록 수정하고 싶다.

0개의 댓글