나는 플러터는 물론이고, 네이티브를 잘 다루지 못한다. 그런데 ios 환경에서 볼 법한 반응형을 구현하라는 지령이 떨어진 것이다..! 내가 구현해야 하는 것은 바로 아래 UI이다.
하단에 있는 input
창을 누르게 되면, 키보드가 슈루룩... 올라가면서 input
창은 물론이고, 버튼이 생기면서 키보드와 같이 올라가야 한다.
나는 React로 웹뷰를 구현하고 있었기 때문에, 컴퓨터에서 이 환경을 바로 확인하기 어려웠다. 그래서 컴퓨터랑 연결된 IP 주소를 알아내서 사파리에서 개발 환경을 열어보며 열심히 삽질하며 구현을 해보았다.
으아아 복잡한 IOS!!!!!!
안드로이드는 이러한 문제점을 생각하지 않아도 된다. 왜냐하면 키보드가 차지하는 만큼 viewport로 다시 조절되기 때문에, main
레이아웃 컨테이너에 viewport 관련된 반응형 구현만 잘 되어 있다면 별 걱정을 안해도 되기 때문이다. 하지만, IOS는 다르다. viewport
를 조절하는 것이 아니고, document
자체를 키보드 높이 만큼 밀어올려버린다.
굉장히 참고하기 좋은 사진이 있어 첨부한다. (출처)
IOS는 보여지고 있는 viewport
는 그대로이지만, 우리가 확인할 수 있는 시각적 viewport가 줄어들어, 사용자가 버튼을 찾아 스크롤하여 내려가야 하는 불편함이 존재할 것이다.
키보드가 생성되게 되면 document
가 키보드의 뒤쪽의 가상 영역으로 스크롤된다. 그렇게 스크롤이 되다가, document가 키보드 뒤쪽의 가상영역의 하단에 닿게 되면, 그때부터 내부의 html 태그가 스크롤이 된다.
영상으로 함께 보자..지금 이 처참한 상황을...
자동으로 document
가 밀려 올라간다. 가상의 배경이 있는 것처럼 작동하게 된다.
이제 내가 원하는 구현 상황은 버튼만 위로 딸려 올라가서 footer의 fixed 역할을 하게 하는 효과를 만들고, html이 딸려 올라가는 상황을 방지하고 싶다.
useEffect(() => {
const handleVisualViewPortResize = () => {
const currentVisualViewport = Number(window.visualViewport?.height)
if(divRef){
divRef.current!.style.height = `${currentVisualViewport - 30}px`
window.scrollTo(0, 40)
}
if (window.visualViewport){
window.visualViewport.onresize = handleVisualViewPortResize;
}
}, [])
먼저, 해당 로직을 해결할 handleVisualViewPortResize
라는 함수를 만든다. 현재 보이는 viewport
의 높이를 받아온다.
여기서 divRef
는 해당 스크롤을 담당할 수 있는 전체 div를 의미하는 건데, 전체 div의 viewport
크기를 재조정함으로써 스크롤을 조작할 수 있는 것이다.
키보드 추가 기능에 대한 공간은 남겨주어야 하므로 현재 viewport
공간에서 30px를 남겨주고, 헤더의 반 정도 보이는 40px
정도의 스크롤로 옮겨준다.
만약, visualViewport
의 값이 있으면 만들어 둔 핸들러를 실행하는 방식으로 수행한다.
지금 내가 만들고 있는 컴포넌트는 DailyQuestion을 받는 컴포넌트이다. 해당 컴포넌트에서 쓸데없이 많은 함수를 작성하였으므로, input 키보드 IOS 처리를 할 수 있는 커스텀 훅으로 분리하여 다른 곳에서도 재사용 할 수 있도록 하자
현재 TIFY 서비스에서 16px 이하의 폰트를 사용하다보니, 자동으로 확대가 되고 있었다. (아오 폰트 사이즈 딱 16px임 ㅠㅠ)
위의 영상에서 확인할 수 있듯이, input
창을 누르면 화면이 불필요하게 확대된다. 이를 방지하기 위하여 폰트 사이즈를 늘린다는 1차원적인 사고는 디자이너분께서 우리의 전체적인 테마를 위해 만들어놓으신 시스템을 바꾸게 되는 것이므로, 나는 아래와 같은 방법을 선택하였다.
stackoverflow에서 해당 내용을 참고하였다. 전체 meta tag에 아래와 같이 작성하면 된다.
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
결과물이다. 깔끔하게 버튼이 생기면서 키보드 크기에 맞춰 따라 올라가고 있다!