1등 오답노트 앱을 출시했는데 사용자들이 앱을 다운로드받아도 참여율이 적어서 고민이었습니다.
일단 인터페이스가 생소해서 사용자들이 공감하지 못하는 것인지 의심했습니다.
그래서 아래과 같은 튜토리얼 기능을 구현해 보았습니다.
어떻게 구현할 것인가?
일단 처음에 두 가지 방법을 생각했었습니다.
- 화면마다 튜토리얼 데이터와 컴포넌트를 관리하는 방법
- Context에서 모든 페이지의 튜토리얼 데이터와 컴포넌트를 관리하는 방법
이 중에서 두 번째 방법을 선택했습니다.
1등 오답노트 앱은 단순해 보여도 내부적으로 은근히 많은 화면이 있고, 설명해야 할 중요 기능만 23개였습니다.
화면마다 튜토리얼 데이터와 컴포넌트를 관리한다면 중복되는 코드가 많아질 것 같았습니다. 그리고 탭 네비게이션에 포함되지 않은 화면은 새로 로드할 때마다 튜토리얼을 실행했었는지 확인해야 하는 단점도 있습니다.
하지만 튜토리얼을 표시할 화면이 한 두개면 첫 번째 방법도 괜찮아 보입니다.
어떤 라이브러리를 사용할 것인가?
처음에는 리액트 네이티브에서 제공하는 기본 컴포넌트인 Animated를 사용해서 직접 만들 생각이었습니다.
그런데 만드는 도중 강조표시되어야 하는 구멍은 단순히 배경 컴포넌트 위에 올라가야 하는 것이 아니라 배경 컴포넌트를 지우고 안쪽의 뷰를 보여주어야 했습니다. 하지만 이런 기능은 리액트 네이티브에서 기본적으로 제공하는 컴포넌트로는 불가능하다고 알고 있습니다.
react-native-svg 라이브러리를 사용해서 직접 그리는 방법도 있지만 svg는 잘 다루지 못하고, 구멍에 애니메이션을 적용하기도 만만치 않아 보였습니다.
다행히 react-native-hole-view라는 라이브러리가 있었습니다.
이 라이브러리는 한 개 이상의 구멍의 x, y 좌표와 크기 정보를 받아서 보여주는 HoleView 컴포넌트를 제공합니다.
그런데 문제가 있었습니다.
- HoleView 컴포넌트는 안드로이드의 경우 상태바를 제외한 높이를 사용하고, iOS의 경우 화면 전체 높이를 사용합니다.
- 안드로이드의 경우 소프트키와 상태바, iOS의 경우 홈 인디케이터 높이가 기기(iOS 기기도 마찬가지)마다 다릅니다.
- Dimentions.get('screen')으로 구한 높이는 상태바와 소프트키, 홈 인디케이터를 포함한 높이입니다. 이 높이를 사용해서 HoleView에 y 좌표를 주면 운영체제와 기기마다 구멍의 높이가 달라집니다.
일단 안드로이드에서는 react-native-extra-dimensions-android 라이브러리를 사용해서 상태바와 소프트키 높이를 얻을 수 있습니다.
그리고 iOS에서는 HoleView가 상태바를 포함한 높이를 사용하기 때문에 상태바의 높이는 고려하지 않아도 됩니다. 하지만 문제는 홈 인티케이터입니다. 노치 디자인의 아이폰(아이폰X~?)은 더 큰 상태바와 홈 인디케이터 높이를 가지고 있습니다. 아이패드는 화면비가 1.44를 넘지 않고, 너비가 크며, 상태바는 작고, 프로 9.7부터 홈 인디케이터를 가지고 있습니다. 저는 이 세 가지를 통해서 안전한 화면 영역을 유추했습니다. 그리고 iOS에서 react-native-status-bar-height 라이브러리를 사용해서 상태바의 높이를 얻을 수 있습니다.
react-native-iphone-x-helper 라이브러리에서 아이폰의 홈 인디케이터 높이를 구할 수 있다고 했지만, (테스트x) 아이패드에서는 전혀 작동하지 않았기 때문에 사용하지 않았습니다.
제가 사용한 코드를 공유하지는 않겠습니다. 저도 이 문제는 완벽하게 해결하지 못했기 때문입니다. 일단 테스트하는 기기에서는 동일한 위치에 표시되도록 했는데, 다른기기에서는 확인하지 못했습니다.
어쨌든 HoleView를 위해 사용되는 조정된 높이값을 heightForHoleView라는 변수에 넣어 heightForHoleView 변수를 기준으로 y 좌표를 주었습니다.
Context 구현
Context 설정
튜토리얼 Context(TutorialProvider)에서는 3개의 함수와 값을 제공합니다. TutorialProvider로 앱의 최상단을 감싸주면 됩니다. 튜토리얼이 실행될 때만 랜더링에 관여하기 때문에 최상단에 위치시키는게 좋습니다.
하나씩 살펴보겠습니다.
setTutorial
튜토리얼을 사용자에게 보여줄 때 사용하는 함수입니다.
- visible: 튜토리얼을 보일지 말지 결정합니다.
- holes: 다수의 구멍 위치와 각 구멍의 텍스트 정보입니다. 튜토리얼 화면을 터치할 때마다 다음 구멍으로 이동합니다.
- onLastPress: HoleView에서 마지막 구멍을 표시할 때 화면을 터치하면 실행될 함수입니다. 이 함수 안에서 setTutorialList를 사용해서 튜토리얼 실행 기록을 기기에 저장합니다.
tutorialList
사용자의 튜토리얼 실행 기록입니다. 훅이기 때문에 변경되면 Context 내부의 모든 컴포넌트가 인식할 수 있습니다.
하지만 사용자가 23개의 튜토리얼을 모두 보면, 이후에는 더 이상 랜더링에 관여하지 않습니다.
setTutorialLIst
tutorialList가 의존성 변수로 설정되어 있습니다. 변경될 값만 listForEdit에 넣어서 가장 최근의 tutorialList와 병합후 기기에 저장합니다.
저는 이 3개의 Context를 useTutorial 함수를 사용해서 이하 모든 컴포넌트에서 사용할 수 있도록 했습니다.
전체코드
여기서 사용된 타입은 2편 Component에서도 사용됩니다.
스크린별로 튜토리얼 실행여부를 관리해주는 함수들입니다.
'리액트 네이티브' 카테고리의 다른 글
리액트 네이티브 튜토리얼 기능 구현3 - Example (0) | 2021.03.21 |
---|---|
리액트 네이티브 튜토리얼 기능 구현2 - Components (0) | 2021.03.21 |
리액트 네이티브 앱의 소스 코드 보호 (0) | 2020.12.17 |
[인스타그램 클론코딩] 댓글 UI 구현3 - 원하는 컴포넌트 위치로 스크롤 (0) | 2020.06.04 |
[인스타그램 클론코딩] 댓글 UI 구현2 - 스택 네비게이션을 이용한 댓글창 (0) | 2020.06.04 |