[Flutter] - Hold Press Button 만들기 (+ pub.dev 배포)

최근에 여러 앱을 사용하다보면, 버튼을 꾹 누르고 일정한 시간이 지났을 때 결과가 나타나는 그런 UI 경험한 적이 있었다.

 

간단하게 만든 이미지를 미리 추가하여 설명하자면, 버튼을 누르고 일정시간이 지나면 그에 맞는 결과가 나오게끔 만드는게 오늘의 목표이다.

 

Progress를 표현할 shadow를 표현하기 위해 Stack 구조를 사용하기로 하였다. 

또한 AnumationController를 이용하여 값을 체크하였고, 만약 버튼이 끝까지 가지않고 땠을 경우 원래대로 돌아오도록 하였다.

 

class HoldPressButton extends StatefulWidget {
  String? contents;
  final Color? backgroundColor;
  final double? textSize;
  final int pressTime;
  final Color? fontColor;
  final FontWeight? textWeight;
  final Function? pressFunc;

  HoldPressButton({
    required this.pressTime,
    this.contents,
    this.backgroundColor,
    this.textSize,
    this.fontColor,
    this.textWeight,
    required this.pressFunc,
    super.key,
  });

  @override
  State<HoldPressButton> createState() => _HoldPressButtonState();
}

class _HoldPressButtonState extends State<HoldPressButton>
    with SingleTickerProviderStateMixin {
  AnimationController? controller;

  @override
  void initState() {
    controller = AnimationController(
        vsync: this, duration: Duration(seconds: widget.pressTime));
    controller!.addListener(() {
      setState(() {});
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) => controller!.forward(),
      onTapUp: (_) {
        if (controller!.value >= 1.0) {
          // active
          widget.pressFunc!.call();
        } else {
          if (controller!.status == AnimationStatus.forward) {
            controller!.reverse();
          }
        }
      },
      child: Stack(
        children: [
          Positioned(
            top: 0,
            bottom: 0,
            child: Container(
              width: MediaQuery.of(context).size.width,
              decoration: BoxDecoration(
                  gradient: LinearGradient(
                      colors: widget.backgroundColor == null
                          ? [Colors.amber.withOpacity(0.4), Colors.amber]
                          : [
                              widget.backgroundColor!.withOpacity(0.4),
                              widget.backgroundColor!
                            ],
                      begin: Alignment.topLeft,
                      end: Alignment.bottomRight)),
            ),
          ),
          Positioned(
            top: 0,
            bottom: 0,
            child: Container(
              width: MediaQuery.of(context).size.width *
                  (controller == null ? 1 : controller!.value),
              decoration: BoxDecoration(
                  gradient: LinearGradient(colors: [
                Colors.grey.withOpacity(0.3),
                Colors.grey.withOpacity(0.5)
              ], begin: Alignment.topLeft, end: Alignment.bottomRight)),
            ),
          ),
          Align(
            alignment: Alignment.center,
            child: Text(
              widget.contents ?? "",
              style: TextStyle(
                color: widget.fontColor ?? Colors.white,
                fontSize: widget.textSize ?? 30,
              ),
            ),
          )
        ],
      ),
    );
  }
}

전체 코드는 다음과 같다.

 

Pub.dev에도 배포했으니 많관부

https://pub.dev/packages/long_hold_down_press_button

 

long_hold_down_press_button | Flutter Package

hold_down_press_button.

pub.dev

전체 코드

https://github.com/Myeongcheol-shin/hold_down_press_button