Flutter; Container로 커스텀 애니메이션 (눌림 효과) 버튼 구현하기

    플러터에서 버튼의 종류는 TextButton, ElevatedButton, OutlinedButton이 세가지이다. 

    위 세가지 버튼에도 클릭시 기본 효과가 존재하지만, 내가 원하는 느낌은 눌려서 작아지는 느낌이었다. 그래서 두고두고 쓰고자 작성함.

     

     

     

    아래 위젯은 Flutter Hooks를 사용하여 작성됨.

    flutter_hook가 싫다면 걍 useState부분을 setState로 대체해서 사용하면 될듯함.

     

     

     

    먼저 flutter_hooks를 프로젝트에 추가

    flutter pub add flutter_hooks

     

    아래의 위젯에 사용되는 flutter_hooks의 함수는 useState()이다. 이를 사용하면 statefulWidget을 사용한 코드보다 훨씬 길이가 단축된다.

    var data = useState(*)에서 *자리에 initialData을 입력. 입력시 data의 자료형은 ValueNotifier<*의 자료형>이 된다.

    data.value로 값을 사용하면 됨.

     

     

     

    위젯을 만들건데, AnimatedContainer와 AnimatedDefaultTextStyle를 사용하고, 이들을 GestureDetector로 wrap하여 onTapUp과 onTapDown으로 버튼 효과주기.

    탭업 할때 isClicked를 false로 변경 + 함수 실행. 탭다운시 isClicked를 true로 변경. 

     

    Widget의 속성들을 optional parameter로 입력받도록 작성할 것임.

     

     

    어떤 값들을 입력받을지 구상한다.

    • text: 버튼에 표시될 텍스트. (String)
    • defaultSize: 클릭 전 기본 크기, Offset의 dx는 width이고 dy는 height. (Offset)
    • clickedSize: 클릭시 줄어든 크기, Offset의 dx는 width이고 dy는 height. (Offset)
    • defaultFontSize: 클릭 전 기본 폰트 크기. (double)
    • clickedFontSize: 클릭시 줄어든 폰트 크기. (double)
    • defaultColor: 클릭 전 기본 컨테이너 색상. (Color)
    • clickedFontSize: 클릭시 컨테이너 색상. (Color)
    • circularRadius: Container의 BorderRadius.circular의 값 (double)
    • buttonDuration: Container의 Animation의 시간길이(밀리초). (int)
    • textDuration: Container안의 Text의 Animation의 시간길이(밀리초). (int)
    • textColor: 버튼에 표시될 텍스트의 색상. (Color)
    • onTap_: 버튼 클릭시 발생할 이벤트를 입력받음. (Function())

    코드:

    
    Widget animationButton({
      required String text,
      Offset defaultSize = const Offset(100, 105), //(width,height)
      Offset clickedSize = const Offset(100, 105), //(width,height)
      double defaultFontSize = 15,
      double clickedFontSize = 14,
      required Color defaultButtonColor,
      required Color clickedButtonColor,
      double circularRadius = 10,
      int buttonDuration = 300,
      int textDuration = 300,
      required Color defaultTextColor,
      required Color clickedTextColor,
      required void Function() onTap_,
    }) {
      var isClicked = useState(false);
      return GestureDetector(
        onTapDown: (_) => isClicked.value = true,
        onTapUp: (_) {
          isClicked.value = false;
          onTap_();
        },
        child: AnimatedContainer(
          duration: Duration(milliseconds: buttonDuration),
          width: isClicked.value ? clickedSize.dx : defaultSize.dx,
          height: isClicked.value ? clickedSize.dy : defaultSize.dy,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(circularRadius),
            color: isClicked.value ? clickedButtonColor : defaultButtonColor,
          ),
          child: Center(
            child: AnimatedDefaultTextStyle(
              duration: Duration(milliseconds: textDuration),
              style: TextStyle(
                color: isClicked.value ? clickedTextColor : defaultTextColor,
                fontSize: isClicked.value ? clickedFontSize : defaultFontSize,
              ),
              child: Text(text),
            ),
          ),
        ),
      );
    }

     

     

    적용:

    import 'package:flutter/material.dart';
    import 'package:flutter_hooks/flutter_hooks.dart';
    
    class CustomButton extends HookWidget {
      const CustomButton({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: animationButton(
            text: 'Button',
            defaultSize: const Offset(110, 50),
            clickedSize: const Offset(108, 48),
            defaultFontSize: 14,
            clickedFontSize: 13,
            defaultButtonColor: const Color(0xFF2D2D36),
            clickedButtonColor: const Color(0xFF282830),
            defaultTextColor: Colors.white,
            clickedTextColor: Colors.white70,
            onTap_: () {
              print('ClickEvent');
            },
          ),
        );
      }
    }

     

     

    참고:

     

    AnimatedContainer class - widgets library - Dart API

    Animated version of Container that gradually changes its values over a period of time. The AnimatedContainer will automatically animate between the old and new values of properties when they change using the provided curve and duration. Properties that are

    api.flutter.dev

     

     

    AnimatedDefaultTextStyle class - widgets library - Dart API

    Animated version of DefaultTextStyle which automatically transitions the default text style (the text style to apply to descendant Text widgets without explicit style) over a given duration whenever the given style changes. The textAlign, softWrap, overflo

    api.flutter.dev

     

    댓글