Foggy day

[Flutter] Button Widget - 예제(ElevatedButton, TextButton, OutlinedButton, IconButton) 본문

Flutter/Flutter widget

[Flutter] Button Widget - 예제(ElevatedButton, TextButton, OutlinedButton, IconButton)

jinhan38 2023. 3. 26. 17:09

 

 

 

이번 포스팅에서는 Button 위젯의 예제를 만들어봤습니다.

 

 

Flutter에서 클릭에 대한 액션은 GestureDetector, InkWell, Button을 사용해 구현합니다. Button 위젯들에는 기본적으로 설정된 UI가 있어서 간단히 구현하기에는 GestureDetector와 InkWell이 더 편리합니다. 하지만 클릭 이벤트를 좀 더 다이내믹하게 구현하고 싶다면 Button 위젯들을 사용하는 것도 좋은 방법입니다.

 

 

ElevatedButton, TextButton, OutlinedButton 버튼은 동일한 방법으로 style을 설정할 수 있습니다. 그래서 셋 중 한개의 버튼을 선택해서 스타일을 입혀 사용하고 있습니다(개발자마다 다름). IconButton은 다른 특성들이 있기 때문에 따로 구현했습니다.

 

 

버튼 스타일에는 특성이 워낙 많기 때문에 결과 이미지, 영상, 코드로 대체하겠습니다. 대부분의 특성들을 사용했고, 각각의 특성은 주석으로 달아 놓았습니다. 플러그인을 사용하거나 의존성 문제가 없으니 그대로 복사한 후 구현해 보시는 것을 추천드립니다. 

 

 

 

 

 

 

 

import 'package:flutter/material.dart';

class ButtonScreen extends StatefulWidget {
  const ButtonScreen({Key? key}) : super(key: key);

  @override
  State<ButtonScreen> createState() => _ButtonScreenState();
}

class _ButtonScreenState extends State<ButtonScreen> {
  // strokeAlign에 대한 자세한 자료
  // https://api.flutter.dev/flutter/painting/BorderSide/strokeAlign.html

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("ButtonScreen"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _elevatedButton(),
            const SizedBox(height: 60),
            _textButton(),
            const SizedBox(height: 60),
            _outLinedButton(),
            const SizedBox(height: 60),
            _iconButton(),
          ],
        ),
      ),
    );
  }

  Widget _elevatedButton() {
    return ElevatedButton(
      /// onPressed와 onLongPress가 null이면 button이 비활성화됨
      // onPressed: null,
      onPressed: () {
        print('onPressed');
      },

      onLongPress: () {
        print('onLongPress ');
      },

      /// 웹에서 사용됨
      onHover: (value) {
        print('value : $value');
      },
      style: buttonStyle(
          OutlinedBorderType.roundedRectangleBorder, Colors.blue, 10),
      child: const Text(
        "ElevatedButton",
        style: TextStyle(fontSize: 25),
      ),
    );
  }

  Widget _textButton() {
    return TextButton(
      onPressed: () {},
      style: buttonStyle(
          OutlinedBorderType.beveledRectangleBorder, Colors.yellow, -10),
      child: const Text(
        "TextButton",
        style: TextStyle(fontSize: 25),
      ),
    );
  }

  Widget _outLinedButton() {
    return OutlinedButton(
      onPressed: () {},
      style: buttonStyle(OutlinedBorderType.circleBorder, Colors.cyan, 20),
      child: const Text(
        "OutlinedButton",
        style: TextStyle(fontSize: 25),
      ),
    );
  }

  Widget _iconButton() {
    return StatefulBuilder(
      builder: (context, setState) {
        return IconButton(
          onPressed: () {},
          icon: const Icon(Icons.add),
          iconSize: 30,

          /// 아이콘 컬러, 아이콘 자체에 컬러를 입력했다면 그것이 우선됨
          color: Colors.green,

          /// 클릭 했을 때 클릭 영역 배경 컬러
          highlightColor: Colors.blue.withOpacity(0.5),

          /// 버튼 누르고 있을 때 펼쳐지는 splash 컬러
          splashColor: Colors.black,

          /// splash의 영역(반지름)
          splashRadius: 50,

          /// 버튼 비활성화 됐을 때 아이콘 컬러
          disabledColor: Colors.grey,

          focusColor: Colors.purple,

          hoverColor: Colors.blue.shade400,

          mouseCursor: SystemMouseCursors.click,

          // tooltip: "아이콘 버튼",

          style: IconButton.styleFrom(padding: EdgeInsets.zero),
          padding: EdgeInsets.zero,

          /// 아이콘 버튼의 사이즈
          constraints: const BoxConstraints(minHeight: 50, minWidth: 50),
        );
      },
    );
  }

  ButtonStyle buttonStyle(
    OutlinedBorderType shapeType,
    Color backgroundColor,
    double strokeAlign,
  ) {
    return ElevatedButton.styleFrom(
      /// 텍스트의 컬러와 클릭했을 때 splash 컬러 변경
      foregroundColor: Colors.black,

      /// 버튼의 배경 컬러
      backgroundColor: backgroundColor,

      /// 버튼의 형태 변경
      shape: _shape(shapeType),

      /// 버튼의 테두리 설정
      /// shape에서 테두리가 있는 특성인 경우
      /// shape의 설정보다 side의 설정이 우선합니다.
      /// continuousRectangleBorder에는 적용 불가
      /// strokeAlign
      side: BorderSide(color: Colors.red, width: 2, strokeAlign: strokeAlign),

      /// 버튼의 높이 설정, 입체감 부여
      elevation: 5,

      /// 그림자 컬러 elevation이 높아질 수록 진해짐
      shadowColor: Colors.purple,

      /// 버튼의 사이즈 고정
      // fixedSize: const Size(250, 100),

      /// 최소 사이즈 설정
      minimumSize: const Size(200, 70),

      /// 최대 사이즈 설정
      maximumSize: const Size(300, 200),

      /// 버튼 내부 패딩
      padding: EdgeInsets.zero,

      /// 버튼의 애니메이션 동작 시간입니다.
      /// ElevatedButton을 누르고 있으면 버튼이 살짝 올라오는 애니메이션이 있습니다.
      /// 이때 걸리는 시간입니다.
      animationDuration: const Duration(milliseconds: 300),

      /// 자식 위젯의 alignment.
      /// 기본 값은 center
      alignment: Alignment.center,

      /// 버튼 비활성화 됐을 때 버튼 컬러
      disabledBackgroundColor: Colors.grey,

      /// 버튼 비활성화 됐을 때 텍스트 컬러
      disabledForegroundColor: Colors.white,

      /// 버튼 비활성화 됐을 때 마우스 형태(웹 에서만 적용됨)
      disabledMouseCursor: SystemMouseCursors.basic,

      /// 버튼 활성화 됐을 때 마우스 형태(웹 에서만 적용됨)
      enabledMouseCursor: SystemMouseCursors.click,

      tapTargetSize: MaterialTapTargetSize.shrinkWrap,

      /// 'primary' is deprecated
      // primary: ,

      /// 'onPrimary' is deprecated
      // onPrimary: ,

      /// 'onSurface' is deprecated
      // onSurface: ,
    );
  }

  /// 버튼 스타일에서 shape 특성
  OutlinedBorder _shape(OutlinedBorderType type) {
    OutlinedBorder border;
    var borderSide = const BorderSide(color: Colors.red, width: 1);
    var borderRadius = BorderRadius.circular(24);

    switch (type) {
      /// 테두리가 있고, 모서리가 경사진 형태가 됩니다.
      case OutlinedBorderType.beveledRectangleBorder:
        border = BeveledRectangleBorder(
          borderRadius: borderRadius,
          side: borderSide,
        );
        break;

      /// [eccentricity]테두리가 사각형에 맞게 변형되는 비율 정의 0~1.0
      /// 0.0이면 직사각형의 두 변 이상에 닿는 원을 그립니다.
      /// 1.0이면 사각형의 모든 면에 닿는 타원을 그립니다.
      case OutlinedBorderType.circleBorder:
        border = CircleBorder(side: borderSide, eccentricity: 0);
        break;

      /// 직선 면과 둥근 모서리 사이가 부드럽게 연속적으로 전환되는 직사각형 테두리 입니다.
      case OutlinedBorderType.continuousRectangleBorder:
        border = ContinuousRectangleBorder(
            borderRadius: borderRadius, side: borderSide);
        break;

      /// 테두리와 모서리 라운드가 있는 스타일 입니다.
      case OutlinedBorderType.roundedRectangleBorder:
        border = RoundedRectangleBorder(
            side: borderSide, borderRadius: borderRadius);
        break;

      /// 테두리가 항상 반원인 형태
      /// 가로 세로 중에 길이가 긴 쪽으로 반원이 형성 됩니다.
      case OutlinedBorderType.stadiumBorder:
        border = StadiumBorder(side: borderSide);
        break;
      default:
        border = ContinuousRectangleBorder(
            borderRadius: borderRadius, side: borderSide);
        break;
    }

    return border;
  }
}

enum OutlinedBorderType {
  beveledRectangleBorder,
  circleBorder,
  continuousRectangleBorder,
  roundedRectangleBorder,
  stadiumBorder,
}