[Flutter] 인스타 라이브의 좋아요 인터렉션

LOCKED·2021년 11월 6일
25

Interaction

목록 보기
4/7
post-thumbnail

인스타 라이브의 좋아요 인터렉션을 구현해보려 한다.

구현 목표

구현하려는 기능은 다음과 같다.

  1. 버튼을 눌렀을 때,
    1. 좋아요 아이콘이 생성
    2. 생성된 아이콘이 위로 올라가다 사라짐
  2. 버튼을 길게 눌렀을 때,
    1. 좋아요 아이콘이 일정시간마다 생김
    2. 생성된 아이콘이 위로 올라가다 사라짐.

미리보기

이 포스트에 기술된 내용에 조금만 더 보태면 아래와 같은 인터렉션을 구현할 수 있다.

개발

터치 이벤트 감지

터치 이벤트를 감지하기 위해 GestureDetector 위젯을 사용하였다.

// 버튼 
GestureDetector(
  onTap: (){},
  onLongPress: (){},
  child: favButton,
),

아이콘 생성

버튼을 터치할 때, 좋아요 아이콘이 생성되어 사라지게 하기 위해서는 어떻게 해야할까?

잘하는 사람이 아니라면 어려운 애니메이션, 인터렉션을 곧바로 개발하는 것에 대해 막연하고 답답할 것이다.

그래서 어렵지 않고 할 수 있는 것부터 해보려한다.

천천히 단계별로 생각해보면, 한 화면에 겹칠 수 있는 구조를 짜야한다.
이는 Flutter에서 Stack 을 사용하여 구현할 수 있다.

Stack(
  children: favIcons,
)

아이콘 위치

favIcons는 어떻게 정의하면 좋을까?

favIcons의 element마다 위치를 잘 조절하면 원하는 모습을 구현할 수 있을 것 같다는 생각이 든다.
Positioned위젯으로 Stack 위젯 내의 자식의 위치를 변경해보았다.

Stack(
  children: [
    Positioned(
      right: 10,
      bottom: 10,
      child: favIcon,
    ),
    Positioned(
      right: 10,
      bottom: 20,
      child: favIcon,
    ),
  ]

혹은, Transform.translate를 사용할 수도 있다.

아직 원하는 목표와는 멀어보이지만, 화면 내에 2개의 아이콘이 생겼다.

아이콘 애니메이션

다음 목표는 하나의 아이콘을 아래에서 위까지 움직이는 것이다.
애니매이션의 값은 0~1로 두고 원하는 위치까지 높이를 변경한다.

AnimatedBuilder(
  animation: animation,
  builder: (BuildContext context, Widget? child) {
    return Transform.translate(
      offset: Offset(0, animation.value * -100),
      child: child,
    );
  },
),

해당 애니메이션을 사용하게 되면 animation value에 따라서 위로 100만큼 이동하게 된다.

동적 아이콘 생성

위의 과정들을 통해서 아이콘을 생성하고, 애니메이션하는 방법을 구현했다.
그렇다면 버튼을 터치하였을 때, 어떻게 아이콘을 생성할까?

간단한 대답일 수 있지만,
터치할 때마다 아이콘 위젯을 추가해주면 된다.
누른 시간을 가지고있는 FavIconData 클래스를 생성하고 터치 이벤트가 발생할 때마다 해당 리스트를 추가한다.

class FavIconData{
  int timestamp; 
  FavIconData(this.timestamp);
}
...
List<FavIconData> favIconDatas= [];
...
addFavIcon(int timestamp){
  favIconDatas.add(FavIconData(timestamp));
}

timestamp를 저장한 이유는 Key의 값으로 사용하기 위함이다. 삭제하고 다시 화면에 렌더링하는 과정에서 개런티를 해주기 위해서 필요하다.

추후, 더 많은 기능을 원한다면 Icon의 Offset, Size 등의 데이터를 추가하면 된다.

동적 아이콘 삭제

위에서 버튼을 누르면 아이콘이 추가되는 간단한 로직을 만들었다.
이제 애니메이션이 끝날 때, 해당 아이콘을 리스트(favIconDatas)에서 remove를 해주면 삭제된다.

if(animation.status == AnimationStatus.complete){
  favIconDatas.removeFirst();
}

프로세스 (중략)

  1. 버튼 터치
  2. favIconDatas에 추가
  3. 애니메이션 시작
    1. Translate, scale, opacity
  4. 애니메이션 종료
  5. favIconDatas에서 항목 삭제

결과

위의 순서대로 개발을 진행하면 위의 이미지와 같은 모습은 아닐지라도 기본적인 흐름은 잡혔을 것이다.

그 이후는 개인의 역량과 상상력을 예시보다 좋은 결과물을 낼 수 있을 것이라 생각된다.

생각보다 어렵지 않은 기능이지만, 구현하고나면 사용자의 흥미를 끌만한, 앱 퀄리티를 높일만한 요소이다.

추가

  • OpacityScale을 조절해 fadeOut 효과를 주면 더 자연스럽다.
  • 터치를 할 때, 진동(haptic feedback)을 주면 좀 더 사용감이 좋다.

해당 인터렉션은 https://play.google.com/store/apps/details?id=com.locked.skein (앱)를 다운로드 하시면 확인할 수 있습니다.

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

profile
Flutter 개발자 :'>

6개의 댓글

comment-user-thumbnail
2022년 3월 10일

안녕하세요! 재밌게 잘 읽었습니다 :) 실제로 구현하고 싶은데, 혹시 소스코드가 공유 가능한지 여쭤봐도 될까요?

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

안녕하세요~ 좋은글 올려주신것보고 따라하다가 마지막에 막히는 부분이 있어 문의드립니다~! ^^; 올려주신글의 마지막 움짤처럼 버튼 연타시 하트 샤샤삭 올라오게는 구현되었는데요~ 동적 아이콘 삭제를 위해.. AnimationStatus.complete 상태이면 배열에서 해당 아이템을 빼도록 하면, 실제 배열에서 아이템이 빠진시점 이후 한번의 터치는 화면에 반응이 없네요 (배열에는 신규 타임스템프가 추가가 되긴 됩니다.) 그 다음에는 또 터치하면 하트가 생겨나구요.. 배열에서 아이템을 빼는 코드 한줄만 주석처리하면 모든 터치에 반응이 잘 되어 하트가 빠지지 않고 생성되는데, 왜 배열에서 빠지는 로직만 들어가면 해당 코드 실행후 1회의 터치가 화면 반응을 건너뛰는걸까요.. ㅠㅠ

답글 달기