ABOUT ME

설명이 필요해?

Today
Yesterday
Total
  • 좋아요 인터렉션을 참고해 만든 커스텀 인터렉션
    IT/Flutter 2024. 6. 12. 15:59
    SMALL

     

     

     

    사내에서 인스타 라이브의 좋아요 인터렉션을 응용하면 구현이 가능할만한 인터렉션 요소를 개발해달라는 요구가 들어와서 한번 공유해보고자 한다.

     

    먼저 맨 아래의 [인스타 라이브의 좋아요 인터렉션] 블로그 글을 참고하면 이해하는데 더욱 도움이 될 것 같다.

     

     

    구현 프로세스

    1. 아이콘 터치
    2. 터치 위치에 인터렉션 요소를 가진 아이템 추가
    3. 애니메이션 종료
    4. 아이템 삭제

     

     

    * 터치 및 해당 위치에 인터렉션 요소를 가진 아이템 추가

     

    터치 위치값을 알기 위해선 GestureDetector 의 onTapDown 콜백 메서드를 활용할 수 있다.

    localPostion 과 globalPosition 을 가져올 수 있는데, 

    globalPostion - 전체 스크린 영역에서 절대위치 값

    localPosition - 탭 한 위젯 내에서의 상대적인 위치 값

    정도로 이해할 수 있다.

     

    어떤 position 을 사용해서 구현해도 무방하지만 나는 커다란 코인버튼 영역 내에서 생성되기를 원했기 때문에 localPosition을 이용하여 구현하였다.

    onTapDown: (details) {
      final localPosition = details.localPosition;
      addTouchInteractionIcon(localPosition);
      widget.onTap.call();
      setState(() {});
    },

     

    void addTouchInteractionIcon(Offset tapPosition) {
      touchInteractionIcons = [
        ...touchInteractionIcons,
        _TouchInteractionIcon(
          key: UniqueKey(),
          tapPosition: tapPosition,
          onAnimationEnd: () {
            _removeTouchInteractionIcon(touchInteractionIcons);
          },
        )
      ];
    }
    

     

    이렇게 position 값을 얻어왔다면 해당 위치에 인터렉션 아이콘을 삽입해준다.

    여기서 주의할 점은 Flutter 프레임워크가 새로 추가된 인터렉션 아이템의 renderobject 를 재사용하게 하면 안된다는 것이다.

    해당 인터렉션 아이템은 생성되는 즉시 TransForm 위젯을 이용하여 위치를 이동하고 transition, opacity, scale 등의 애니메이션을 animationController 을 통해 수행하게 되는데, 재사용을 하게되면 원치않는 인터렉션이 생길수가있다.

     

    Flutter 프레임워크에서 트리내의 위젯의 재사용을 결정하는 방식은 크게 두가지가 있는데,

    먼저 key 가 주어지지 않은 경우 해당 위치의 위젯의 Type 을 이용하여 비교한다. 

    만약 key가 주어진다면 type과 함께 key를 이용하여 비교한다.

     

    따라서 Type 은 같을 수 밖에 없으므로 프레임워크 내부적으로 중복되지않는 키값을 생성해주는 UniqueKey() 메서드를 이용하여 key를 넘겨주게 되면 위와같은 현상을 방지할 수 있다.

     

    * 인터렉션 아이템 

    class _TouchInteractionIcon extends HookWidget {
      const _TouchInteractionIcon({required this.tapPosition, required this.onAnimationEnd, super.key});
    
      final VoidCallback onAnimationEnd;
    
      final Offset tapPosition;
    
      @override
      Widget build(BuildContext context) {
        final animationController = useAnimationController(
          duration: const Duration(milliseconds: 1000),
        );
    
        final initialRotationAngle = useState(_getRotationAngle());
        final initialScale = useState(_getInitialScale());
        final initialXPosition = useState(tapPosition.dx + Random().nextInt(20) - 58.w);
    
        useEffect(() {
          Future.microtask(() {
            animationController.addStatusListener((status) {
              if (status == AnimationStatus.completed) {
                onAnimationEnd.call();
              }
            });
    
            animationController.forward();
          });
    
          () => null;
        }, []);
    
        return AnimatedBuilder(
          animation: animationController,
          builder: (context, child) {
            return Opacity(
              opacity: _getOpacity(animationController.value),
              child: Transform(
                transform: Matrix4.translationValues(
                  ...)

     

    인터렉션 아이템 내부에서는 생성과 동시에 초기 위치, 스케일 등의 인터렉션에 필요한 요소들을 초기화해주고, 애니메이션을 실행하며 Transform 으로 위치를 이동시키고 있다. 


    이에 더하여 원하는 애니메이션 요소들을 추가해주면 더욱 더 멋진 인터렉션을 만들 수 있을것이다.

     

     

    * 참고

    https://velog.io/@locked/Flutter-%EC%9D%B8%EC%8A%A4%ED%83%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C-%EC%A2%8B%EC%95%84%EC%9A%94-%EC%9D%B8%ED%84%B0%EB%A0%89%EC%85%98

     

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

    인스타 라이브의 좋아요 인터렉션은 어떻게 만들까?

    velog.io

     

    LIST
Designed by Tistory.