카카오 웹툰, 안드로이드에서만 제공하는 인터렉션은 무엇일까?

카카오 웹툰

웹툰 플랫폼 중 단연 가장 이쁘다고 할 수 있는 <카카오웹툰>
이번 포스트에서는 해당 앱 속 인터렉션에 대해 작성하려한다.

개발할 내용은 웹툰 뷰어 내부에서 해당 웹툰의 목록을 볼 수 있게 해주는 기능이다.

< 카카오웹툰 > 아비무쌍 188화

위와 같이 동작하는 기능인데 처음 접했을 때 와우했던 포인트 중 하나이다.
디자인 대격변을 하면서 다른 디자인들은 과하다. 라고 생각할 수 있지만 이 기능은 디자인뿐만 아니라 사용성 또한 높다.
(UX를 배운적은 없어 옳은 UX 방향인지는 모르겠다. 다만, 고객의 입장에서 사용했을 때 충분히 만족했다.)

하지만, 이 인터렉션은 독특하게도 Android에서만 제공하는 기능이다.
어떠한 사유인지는 모르겠으나 Web과 iOS에서는 개발을 하지 않은 부분인데 플랫폼별 기획이 달랐던 것인지, A/B테스트를 하는 중인지, 어떤 의도로 다른 경험을 제공하는지는 의문이다.

Web에서는 웹툰 뷰어가 좌우로 펼쳐지지 않고, 위에 오버레이 효과가 나타난다.

< 카카오웹툰 > 아비무쌍 188화

반으로 갈라진 캐릭터

<네이버웹툰 > 초인의시대 2부 10화

애니메이션과 함께 보면 정말 좋은 인터렉션인 것 같은데,
뒤에 있는 웹툰 속 캐릭터가 절반으로 나뉘어 살짝 거부감이 있을 수 있어보인다. 원작을 해치는 느낌 또한 받을 수 있기 때문에 안드로이드서만 적용했나 싶기도 하다.


아무튼 Android에서만 제공하는 이 인터렉션을 모든 플랫폼에서 느낄 수 있게 Flutter로 개발해보려한다.

클라이언트 개발자라면 읽기전에 어떻게 만들지 한 번쯤 생각해보는 것도 좋을 것 같다.

기획

사실 이번 인터렉션 개발의 난이도가 상당히 높아보인다.
"위젯이 좌우로 분할된다니...기존에 개발하던 방식처럼 위젯들만 이용해서는 개발하기 힘들어보이는데? 도대체 어떻게 하는거지?" 라는 의문이 들 수 있다.

하지만, 말로만 표현한다면 굉장히 쉬워질 수 있다.

  1. 이벤트 발생
  2. 화면의 가운데를 중심으로 기준점 생성
    1. 기준점으로부터 왼쪽에 위치한 절반을 왼쪽으로 움직임
    2. 기준점으로부터 오른쪽에 위치한 절반을 오른쪽으로 움직임.
  3. 화면의 가운데에서 웹툰 목록이 보여짐.

여기서 할 수 있는 것들을 제외하고 생각해보자.

이벤트를 발생시키는 트리거(카카오웹툰에서는 버튼)는 어려울 게 없다. GesutureDetector, InkWell, Button, ... 등 이벤트 감지 위젯을 사용하면 된다.
화면의 가운데를 찾는 것도 어렵지 않다. MediaQuery 에서 화면에 대한 정보를 가져올 수 있으니..
왼쪽/오른쪽으로 움직이는 애니메이션도 AnimatedBuilder를 이용하면 된다.
웹툰 목록도 Fade효과를 부여하면된다..


다 쉬워보이는데 그렇지 않은게 하나 있다...
처음 보고 할 수 있을까? 라고 생각되던 것은!!


위젯을 반으로 나누는 것이다.
어떻게 해야 화면에 이미 그려진 위젯을 반으로 나눌 수 있을까?

화면에 있는 것을 그려본 사람은 많아도, 나눠볼 생각을 한 사람은 적을 것 같다.
나 또한, 이 앱을 보기 전까지는 그러했다.

아무튼 이번 인터렉션은 위젯을 반으로 나누기만하면 끝난다.


첫 번째 생각은

  • 위젯을 2개 겹쳐, 절반씩 자른 후 보여주는 것이다.

두 번째 생각은

  • 하나의 위젯을 진짜 반으로 나누는 것이다.

개발

첫 번째 방법과 두 번째 방법의 장단이 있을 것 같다.
결과적으로는 두 가지 방법으로 구현을 해보았는데,
첫 번째 아이디어는 구현하기는 훨씬 간단하지만, 스크롤의 미세한 이슈가 있었다.
두 번째 아이디어는 구현 난이도가 높았지만, 좀 더 완성도가 높은 모습을 보였다.

각각의 방법을 좀 더 자세히 설명하자면, 다음과 같다.

첫 번째 방법, 2개의 위젯 사용하기

<네이버웹툰 > 초인의시대 2부 10화

먼저 ClipPath 위젯을 사용하여 기준이 되는 위젯을 절반으로 나눈다. clipper는 화면의 절반을 자르기 위해 Rect를 사용하였다.


Path getClip(Size size) {
  Path path = Path()..addRect(Rect.fromLTRB(0, 0, size.width / 2, size.height));
  return path;
}

이렇게 두 번 반복하면 하나의 위젯(이미지)처럼 보이게 된다.

<네이버웹툰 > 초인의시대 2부 10화

이 방법은 두 개의 위젯을 절반씩 보여줘 하나의 위젯처럼 보이게 하는 방식이다.


하지만 스크롤 컨트롤러를 동기화 해주지 않으면 양쪽이 각각 따로 노는 문제가 발생한다...

<네이버웹툰 > 초인의시대 2부 10화

ScrollController를 동기화 해주자!

단일 스크롤 컨트롤러를 사용해도 되고, 2개의 스크롤컨트롤러를 사용해도 된다.

leftSC.addListener((){
    rightSC.moveTo(leftSC.offest);
});

스크롤까지 동기화하였다면 이제 쉬운 일들만 남았다.

AnimatedBuilder(
  animation: _animationController,
  builder: (context, child) {
    return Transform.translate(
      offset: Offset(-gap * _animationController.value, 0),
      child: child,
    );
  },
  child: ClipPath(
    clipper: const CustomClipper(),
    child: MyWebToonViewer(),
  ),
),

첫 번째 결과

애니메이션을 만들어주고,... fade 효과를 적용하면 된다.

<네이버웹툰 > 초인의시대 2부 10화

첫 번째 방법은 화면에 렌더링할 대상이 이미지였기에 이런 방식으로 가능했다.

또한 웹툰의 확대, 축소 기능을 넣을거면 부적합하다.

두 번째 방법, 하나의 위젯을 나누기

빠르게 개발을 하기 위해서는 위의 첫 번째 방법 혹은 본인이 생각한 쉬운 방법으로 진행하면 될 것 같다.
...

하나의 위젯을 둘로 나누는 방법을 사용하기 위해서는 RenderRepaintBoundary 을 사용하여 화면에 렌더링 되어있는 것을 이미지로 바꾸고, 해당 이미지를 x좌표의 중점을 기준으로 절반을 나누어 다시 위젯으로 변경하면 된다.
...

결과

이번 포스트에서는 카카오웹툰에 사용된 인터렉션 중 일부를 구현해보았다.
하나의 개발을 할 때, 여러가지의 방법을 생각하는 과정에서 얻는 재미가 상당하다.
좀 더 나은 방법을 모색하고, 현재 상황에서 좋은 결과를 내기 위해 노력하는 과정에서 오는..

나는 두 가지 정도의 방식을 생각했는데, 과연 Android 카카오웹툰에서는 어떤 방식을 사용해서 구현했을지 궁금하다.


아래는 두 번째 방법으로 만든 결과이다.

애니메이션은 DurationCurve, Interval을 조절하여 좀 더 자연스럽고 부드럽게 할 수 있다.


<네이버웹툰 > 초인의시대 2부 10화

좀 더 궁금하시다면, 댓글을 남겨주세요.

profile
Flutter 개발자 :'>

12개의 댓글

comment-user-thumbnail
2021년 12월 1일

안녕하세요! 플러터 주니어 개발자입니다~! 항상 LOCKED님 게시물들 보면서 감탄과 함께 열심히 공부중에 있습니다. 흥미롭고 유익한 게시물들을 올려주셔서 감사합니다! 공부하고난 이후에 해당 게시물들 관련해서 개인 블로그나 개인 프로젝트에 적용해도 될까요? 출처는 당연히 남겨 놓겠습니다!

1개의 답글
comment-user-thumbnail
2021년 12월 7일

안녕하세요..! 게시물 잘 보고있습니다. Flutter로 개발을 해오면서 UI는 자신 있다고 생각했건만.. 갈 길이 멀었다는 걸 씨게 느끼네요.. 굉장합니다..! 궁금한거 있을 때 여쭤봐도 될까요!?

1개의 답글
comment-user-thumbnail
2022년 1월 2일

안녕하세요! 주니어 개발자 입니다! 여러가지 애니메이션 관련 글들 잘 보고 있습니다 :) 다름이 아니라 해당 글의 인터렉션을 따라해보면서 화면을 이미지로 만들고, 애니메이션을 주는 것 까진 구현했는데, 혹시 몇 가지 키워드를 조금 더 알려주실 수 있는지 해서 여쭤봅니다! 현재 변수를 하나 두고, 처음 리스트뷰에서 버튼을 누르면 false->true로 변수를 바꾸면서 이미지로 전환하고, 애니메이션 되게 구현했습니다. 예시 동작 화면처럼 조금 더 부드럽게 처리하고 싶은데, 혹시 찾아 볼만한 키워드를 주시면 감사하겠습니다! (인스타 좋아요 인터렉션도 꽤 어렵게 따라했는데 이건 더하네요 ㅎㅎ...)

2개의 답글
comment-user-thumbnail
2022년 7월 5일

오 flutter 관련 글 읽다가 여기까지 왔는데요 내용이 알차네요ㅎ 좋은글 감사합니다. ^^
추가적으로 보통 이런 인터렉션 구현 솔루션 기획이랑 구현까지 어느 정도 시간이 걸리는지 궁금합니다^^

1개의 답글
comment-user-thumbnail
2022년 12월 13일

너무 잘 보았습니다. 질문이 있어서 질문남겨요
RenderRepaintBoundary 를 통해 위젯을 이미지로 변환은 했지만 해당 이미지를 어떻게 반씩 나눌수 있을까요? 이리 저리 생각해보았는데 잘 안되네요 ㅠ
혹시 키워드를 알수 있을까요? 코드면 더 감사합니다..!

답글 달기