본문 바로가기
Study

28. Flutter로 사용자 인터페이스 구축하기 | Flutter

by 구구 구구 2024. 7. 28.
반응형

내려다보기, dall-e

 

Flutter로 사용자 인터페이스 구축하기: 기본 가이드

 

01. 서론

1) Flutter의 인기와 장점

Flutter는 Google에서 개발한 오픈 소스 UI 소프트웨어 개발 키트(SDK)입니다. Flutter의 가장 큰 장점 중 하나는 한 번의 코드 작성으로 Android와 iOS 모두에서 동작하는 앱을 만들 수 있다는 점입니다. 이는 개발 시간과 비용을 크게 절감할 수 있게 해주며, 유지 보수도 용이하게 만듭니다.

 

또한, Flutter는 고성능의 애니메이션과 그래픽을 제공하여 사용자 경험(UX)을 크게 향상시킬 수 있습니다. Flutter는 Skia 그래픽 엔진을 사용하여 프레임워크 레벨에서 매끄럽고 빠른 애니메이션을 구현할 수 있습니다. 이 외에도, Dart 언어의 JIT(Just In Time) 컴파일을 통해 개발자가 코드를 즉시 테스트하고 디버깅할 수 있어 생산성이 높아집니다.

 

Flutter의 또 다른 장점은 방대한 위젯 라이브러리입니다. Flutter는 다양한 기본 및 Material Design 위젯을 제공하여 개발자가 쉽게 UI를 구성하고 사용자 경험을 개선할 수 있습니다. 이러한 위젯들은 커스터마이징이 용이하며, 다양한 레이아웃과 상호작용을 구현할 수 있습니다.

2) Flutter로 UI를 구축하는 이유

Flutter로 UI를 구축하는 이유는 여러 가지가 있습니다. 첫째, Flutter는 빠른 개발 속도를 제공합니다. Hot Reload 기능을 통해 개발자는 코드를 변경하고 즉시 결과를 확인할 수 있어 개발 속도가 매우 빨라집니다. 이는 개발자에게 큰 장점이 되며, 반복적인 테스트와 피드백 사이클을 크게 단축시킵니다.

 

둘째, Flutter는 뛰어난 성능을 제공합니다. Dart 언어의 AOT(Ahead Of Time) 컴파일을 통해 네이티브 성능을 보장하며, 고급 애니메이션과 그래픽을 지원합니다. 이는 특히 게임이나 복잡한 애니메이션이 필요한 애플리케이션에서 큰 장점을 제공합니다.

 

셋째, Flutter는 우수한 커뮤니티와 풍부한 자료를 제공합니다. 많은 개발자들이 Flutter를 사용하고 있으며, 이를 지원하는 커뮤니티가 활발하게 운영되고 있습니다. 또한, 공식 문서와 다양한 튜토리얼이 제공되어 초보자도 쉽게 시작할 수 있습니다.

 

02. Flutter로 시작하기

1) Flutter와 Dart 소개

Flutter는 Google에서 개발한 크로스 플랫폼 UI 툴킷으로, Android, iOS, 웹, 데스크탑 등 여러 플랫폼에서 네이티브 앱을 개발할 수 있습니다. Flutter의 기본 프로그래밍 언어는 Dart입니다. Dart는 Google에서 개발한 객체 지향 언어로, 빠른 실행 속도와 간편한 문법을 제공합니다.

 

Dart의 장점 중 하나는 JIT(Just In Time) 컴파일과 AOT(Ahead Of Time) 컴파일을 모두 지원한다는 점입니다. 개발 단계에서는 JIT 컴파일을 통해 빠른 코드 수정과 테스트가 가능하며, 배포 단계에서는 AOT 컴파일을 통해 네이티브 성능을 제공합니다.

2) Hello World 예제

Flutter에서 "Hello, world" 앱을 만드는 과정은 매우 간단합니다. 기본적인 예제를 통해 Flutter의 구조와 동작 방식을 이해할 수 있습니다.


flutter create hello_world
        

생성된 프로젝트 디렉토리로 이동하여 lib/main.dart 파일을 엽니다. 기본적으로 제공되는 코드를 다음과 같이 수정합니다:


import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello, Flutter!'),
        ),
        body: Center(
          child: Text('Hello, world!'),
        ),
      ),
    );
  }
}
        

이 코드는 Flutter 애플리케이션의 기본 구조를 나타냅니다. runApp() 함수는 주어진 위젯을 위젯 트리의 루트로 만듭니다. MyApp 클래스는 StatelessWidget을 상속받아 build() 메서드를 구현합니다. MaterialApp 위젯은 앱의 루트 위젯으로, Scaffold 위젯을 사용하여 앱의 기본 레이아웃을 구성합니다.

 

Scaffold는 기본적인 머티리얼 디자인 레이아웃 구조를 제공하는데, 여기서는 AppBarCenter 위젯을 포함합니다. AppBar는 상단의 제목 표시줄을 제공하고, Center는 자식 위젯을 중앙에 배치합니다. Text 위젯은 "Hello, world!" 텍스트를 표시합니다.

 

이 코드를 실행하면 화면 중앙에 "Hello, world!"라는 텍스트가 표시된 간단한 애플리케이션이 생성됩니다.


|--------------------------------|
|          Hello, Flutter!       |
|--------------------------------|
|                                |
|                                |
|         Hello, world!          |
|                                |
|                                |
|--------------------------------|
        

이러한 기본 예제를 통해 Flutter의 위젯 기반 UI 구성 방식을 쉽게 이해할 수 있습니다. 다양한 위젯을 조합하여 복잡한 UI를 구성할 수 있으며, Flutter의 강력한 기능을 활용하여 효율적으로 애플리케이션을 개발할 수 있습니다.

 

03. 기본 위젯 소개

1) Text 위젯

Text 위젯은 Flutter에서 텍스트를 표시하는 가장 기본적인 위젯입니다. 다양한 스타일을 적용할 수 있으며, 글꼴 크기, 색상, 굵기 등을 손쉽게 설정할 수 있습니다. 예를 들어, 다음과 같이 텍스트를 표시할 수 있습니다:


Text(
  'Hello, Flutter!',
  style: TextStyle(
    fontSize: 24,
    color: Colors.blue,
    fontWeight: FontWeight.bold,
  ),
);
        

이 코드를 실행하면 파란색으로 굵게 표시된 "Hello, Flutter!" 텍스트가 출력됩니다.

2) Row와 Column 위젯

RowColumn 위젯은 각각 가로와 세로 방향으로 위젯을 배열하는 데 사용됩니다. Row 위젯은 자식 위젯을 가로로 배치하고, Column 위젯은 자식 위젯을 세로로 배치합니다. 예를 들어, 두 위젯을 조합하여 다음과 같이 사용할 수 있습니다:


Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text('Hello,'),
    Text('Flutter!'),
  ],
);
        

이 코드를 실행하면 "Hello,"와 "Flutter!" 텍스트가 가로로 나란히 배치됩니다. mainAxisAlignment 속성을 사용하여 정렬 방식을 조정할 수 있습니다.


Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text('Hello,'),
    Text('Flutter!'),
  ],
);
        

이 코드를 실행하면 "Hello,"와 "Flutter!" 텍스트가 세로로 나란히 배치됩니다.

3) Stack 위젯

Stack 위젯은 자식 위젯을 겹쳐서 배치할 수 있게 해줍니다. Positioned 위젯을 사용하여 각 자식 위젯의 위치를 지정할 수 있습니다. 예를 들어, 다음과 같이 Stack 위젯을 사용할 수 있습니다:


Stack(
  children: [
    Container(
      width: 100,
      height: 100,
      color: Colors.red,
    ),
    Positioned(
      left: 20,
      top: 20,
      child: Container(
        width: 50,
        height: 50,
        color: Colors.blue,
      ),
    ),
  ],
);
        

이 코드를 실행하면 빨간색 사각형 위에 파란색 사각형이 겹쳐진 형태로 출력됩니다.

4) Container 위젯

Container 위젯은 다양한 속성을 설정하여 사각형 영역을 생성하는 데 사용됩니다. 배경색, 테두리, 그림자 등을 적용할 수 있으며, 패딩과 마진도 설정할 수 있습니다. 예를 들어, 다음과 같이 Container 위젯을 사용할 수 있습니다:


Container(
  width: 100,
  height: 100,
  padding: EdgeInsets.all(10),
  margin: EdgeInsets.all(20),
  decoration: BoxDecoration(
    color: Colors.green,
    border: Border.all(color: Colors.black, width: 2),
    borderRadius: BorderRadius.circular(10),
    boxShadow: [
      BoxShadow(
        color: Colors.grey,
        offset: Offset(2, 2),
        blurRadius: 5,
      ),
    ],
  ),
  child: Center(
    child: Text('Hello'),
  ),
);
        

이 코드를 실행하면 녹색 배경의 사각형 안에 "Hello" 텍스트가 중앙에 위치한 형태로 출력됩니다.

 

04. Material Components 사용하기

1) MaterialApp 위젯

MaterialApp 위젯은 Flutter 애플리케이션의 기본 구조를 설정하는 데 사용됩니다. 머티리얼 디자인을 따르는 애플리케이션을 구축할 때 유용하며, 테마와 라우팅을 쉽게 설정할 수 있습니다. 예를 들어, 다음과 같이 MaterialApp을 사용할 수 있습니다:


MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  home: MyHomePage(),
);
        

이 코드를 실행하면 기본 테마가 적용된 Flutter 애플리케이션이 생성됩니다.

2) AppBar와 Scaffold 사용법

AppBarScaffold 위젯은 머티리얼 디자인의 기본 레이아웃 구조를 설정하는 데 사용됩니다. AppBar는 상단에 위치한 앱 바를 생성하고, Scaffold는 앱의 기본 레이아웃을 제공합니다. 예를 들어, 다음과 같이 사용할 수 있습니다:


Scaffold(
  appBar: AppBar(
    title: Text('My Flutter App'),
  ),
  body: Center(
    child: Text('Hello, world!'),
  ),
);
        

이 코드를 실행하면 상단에 "My Flutter App"이라는 제목의 앱 바가 있고, 중앙에 "Hello, world!" 텍스트가 표시된 레이아웃이 생성됩니다.

3) FloatingActionButton 활용

FloatingActionButton은 화면 하단에 떠 있는 액션 버튼을 생성하는 데 사용됩니다. 일반적으로 중요한 액션을 강조하기 위해 사용됩니다. 예를 들어, 다음과 같이 사용할 수 있습니다:


Scaffold(
  appBar: AppBar(
    title: Text('My Flutter App'),
  ),
  body: Center(
    child: Text('Hello, world!'),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      // 버튼이 눌렸을 때의 동작
    },
    child: Icon(Icons.add),
  ),
);
        

이 코드를 실행하면 "Hello, world!" 텍스트가 중앙에 표시되고, 화면 하단에 + 아이콘이 있는 플로팅 액션 버튼이 생성됩니다. 버튼을 누르면 지정된 동작이 실행됩니다.

 

이와 같은 기본 위젯과 Material Components를 활용하여 Flutter 애플리케이션을 구축하면, 깔끔하고 반응성 높은 UI를 손쉽게 만들 수 있습니다.

 

05. 제스처 처리

1) GestureDetector 소개

GestureDetector 위젯은 사용자 입력을 감지하는 데 사용됩니다. 시각적으로 아무것도 표시하지 않지만, 터치, 탭, 드래그 등의 제스처를 감지하여 대응할 수 있습니다. GestureDetector는 다양한 콜백을 제공하여 제스처에 반응할 수 있게 해줍니다. 예를 들어, 단일 탭, 더블 탭, 길게 누르기 등을 감지할 수 있습니다.

2) 다양한 제스처 인식 예제

다양한 제스처를 감지하는 예제를 살펴보겠습니다.


GestureDetector(
  onTap: () {
    print("Tap detected");
  },
  onDoubleTap: () {
    print("Double tap detected");
  },
  onLongPress: () {
    print("Long press detected");
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
    child: Center(
      child: Text(
        'Tap me',
        style: TextStyle(color: Colors.white),
      ),
    ),
  ),
);
        

이 코드를 실행하면 파란색 사각형이 표시되고, 사용자가 사각형을 탭하면 "Tap detected", 더블 탭하면 "Double tap detected", 길게 누르면 "Long press detected"라는 메시지가 콘솔에 출력됩니다.

또 다른 예로, 드래그 제스처를 감지하는 코드를 살펴보겠습니다.


GestureDetector(
  onPanUpdate: (details) {
    print("Dragging: ${details.localPosition}");
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.green,
    child: Center(
      child: Text(
        'Drag me',
        style: TextStyle(color: Colors.white),
      ),
    ),
  ),
);
        

이 코드를 실행하면 사용자가 사각형을 드래그할 때마다 드래그 위치가 콘솔에 출력됩니다. onPanUpdate 콜백은 드래그하는 동안 계속 호출되어, 제스처의 위치를 추적할 수 있습니다.

 

06. 상태 관리와 StatefulWidget

1) StatefulWidget과 State의 차이

Flutter에서는 UI를 구성하는 위젯이 크게 두 가지로 나뉩니다: StatelessWidgetStatefulWidget. StatelessWidget은 상태가 없는 위젯으로, 한 번 생성되면 변경되지 않습니다. 반면, StatefulWidget은 상태를 가질 수 있으며, 상태가 변경될 때마다 UI를 다시 빌드합니다.

 

StatefulWidget은 상태를 관리하기 위해 State 객체를 사용합니다. StatefulWidget은 불변이지만, State 객체는 변경될 수 있습니다. State 객체는 StatefulWidget의 상태를 저장하고, 변경 사항이 발생할 때마다 UI를 다시 빌드하는 역할을 합니다.

2) setState() 사용법

setState() 함수는 상태를 변경하고 UI를 업데이트하는 데 사용됩니다. 상태가 변경될 때 setState()를 호출하면, Flutter는 해당 위젯을 다시 빌드하여 변경된 내용을 반영합니다. 예를 들어, 버튼을 눌렀을 때 카운터를 증가시키는 예제를 살펴보겠습니다.


class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
        

이 예제에서는 _counter 상태 변수를 선언하고, _incrementCounter 함수에서 setState()를 호출하여 _counter 변수를 증가시킵니다. 버튼을 누를 때마다 _counter가 증가하고, UI가 업데이트되어 변경된 값이 화면에 표시됩니다.

3) 복잡한 UI의 상태 관리

복잡한 UI에서는 여러 개의 StatefulWidgetState 객체가 상호 작용할 수 있습니다. 이러한 경우, 상태 관리를 체계적으로 수행하는 것이 중요합니다. 상태 관리를 쉽게 하기 위해 Flutter는 다양한 상태 관리 패턴과 라이브러리를 제공합니다.

예를 들어, 상태를 상위 위젯에서 하위 위젯으로 전달하여 UI를 업데이트하는 패턴을 살펴보겠습니다.


class CounterDisplay extends StatelessWidget {
  final int count;

  CounterDisplay({required this.count});

  @override
  Widget build(BuildContext context) {
    return Text(
      'Count: $count',
      style: TextStyle(fontSize: 24),
    );
  }
}

class CounterIncrementor extends StatelessWidget {
  final VoidCallback onPressed;

  CounterIncrementor({required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text('Increment'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Complex UI State Management'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CounterDisplay(count: _counter),
            CounterIncrementor(onPressed: _incrementCounter),
          ],
        ),
      ),
    );
  }
}
        

이 예제에서는 CounterDisplayCounterIncrementor라는 두 개의 StatelessWidget을 사용하여 상태 관리를 분리합니다. _counter 상태는 상위 위젯인 MyHomePage에서 관리되며, 하위 위젯인 CounterDisplayCounterIncrementor에 전달됩니다. 이를 통해 상태 관리가 체계적으로 이루어지고, 각 위젯의 역할이 명확하게 분리됩니다.

 

Flutter의 다양한 상태 관리 패턴을 사용하면 복잡한 애플리케이션에서도 효율적으로 상태를 관리하고, 유지 보수성을 높일 수 있습니다.

 

07. 고급 주제

1) 위젯 라이프사이클 이벤트

StatefulWidget은 여러 라이프사이클 이벤트를 통해 상태를 관리할 수 있습니다. 주요 라이프사이클 이벤트는 다음과 같습니다:

  • initState(): State 객체가 처음 생성될 때 호출됩니다. 초기화 작업을 수행하는 데 사용됩니다. 예를 들어, 애니메이션 컨트롤러나 네트워크 요청 초기화를 여기서 수행할 수 있습니다.
  • dispose(): State 객체가 더 이상 사용되지 않을 때 호출됩니다. 리소스 해제 및 정리 작업을 수행하는 데 사용됩니다. 예를 들어, 타이머를 취소하거나 네트워크 요청을 정리할 때 사용됩니다.
  • didUpdateWidget(): 부모 위젯이 변경될 때 호출됩니다. 이전 위젯과 새로운 위젯을 비교하여 필요한 업데이트를 수행할 수 있습니다.

예를 들어, 애니메이션을 사용하는 경우를 살펴보겠습니다.


class MyAnimatedWidget extends StatefulWidget {
  @override
  _MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}

class _MyAnimatedWidgetState extends State with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: RotationTransition(
          turns: _controller,
          child: FlutterLogo(size: 100),
        ),
      ),
    );
  }
}
        

이 예제에서는 애니메이션 컨트롤러를 초기화하고, 위젯이 사라질 때 컨트롤러를 정리합니다.

2) 키와 글로벌 키 사용하기

키는 위젯의 식별자를 제공하여, Flutter 프레임워크가 위젯을 효율적으로 관리하고 최적화할 수 있도록 도와줍니다. 키는 로컬 키와 글로벌 키로 나뉩니다.

  • 로컬 키: 동일한 부모 아래에서 고유한 키를 제공합니다. 위젯이 재구성될 때 동일한 키를 가진 위젯끼리 매칭됩니다.
  • 글로벌 키: 위젯 트리 전체에서 고유한 키를 제공합니다. 글로벌 키를 사용하면 위젯의 상태를 쉽게 접근하고, 위젯의 위치를 추적할 수 있습니다.

로컬 키 예제:


ListView.builder(
  itemBuilder: (context, index) {
    return ListTile(
      key: ValueKey(index),
      title: Text('Item $index'),
    );
  },
);
        

글로벌 키 예제:


final GlobalKey _scaffoldKey = GlobalKey();

Scaffold(
  key: _scaffoldKey,
  appBar: AppBar(
    title: Text('GlobalKey Example'),
  ),
  body: Center(
    child: ElevatedButton(
      onPressed: () {
        _scaffoldKey.currentState?.showSnackBar(
          SnackBar(content: Text('Hello, Snackbar!')),
        );
      },
      child: Text('Show Snackbar'),
    ),
  ),
);
        

이 예제에서는 GlobalKey를 사용하여 Scaffold의 상태에 접근하고, 버튼을 눌렀을 때 스낵바를 표시합니다.

 

08. 결론

1) Flutter로 UI를 구축하는 것의 이점

Flutter로 UI를 구축하는 것은 여러 가지 이점을 제공합니다:

  • 크로스 플랫폼 개발: 한 번의 코드 작성으로 Android, iOS, 웹, 데스크탑 등 여러 플랫폼에서 동작하는 앱을 만들 수 있습니다.
  • 빠른 개발 속도: Hot Reload 기능을 통해 코드를 변경하고 즉시 결과를 확인할 수 있어 개발 속도가 매우 빠릅니다.
  • 고성능 애니메이션과 그래픽: Skia 그래픽 엔진을 사용하여 매끄럽고 빠른 애니메이션을 구현할 수 있습니다.
  • 방대한 위젯 라이브러리: Flutter는 다양한 기본 및 Material Design 위젯을 제공하여 개발자가 쉽게 UI를 구성하고 사용자 경험을 개선할 수 있습니다.
  • 우수한 커뮤니티와 자료: 많은 개발자들이 Flutter를 사용하고 있으며, 이를 지원하는 커뮤니티가 활발하게 운영되고 있습니다. 공식 문서와 다양한 튜토리얼이 제공되어 초보자도 쉽게 시작할 수 있습니다.

2) 추가 학습 자료 및 참고 링크

Flutter를 더 깊이 학습하기 위해 다음 자료와 링크를 참고할 수 있습니다:

이 자료들은 Flutter를 배우고 이해하는 데 큰 도움이 될 것입니다. Flutter를 통해 멋진 사용자 인터페이스를 구축하고, 다양한 플랫폼에서 동작하는 앱을 개발해 보세요.


관련된 다른 글도 읽어보시길 추천합니다

 

2024.07.24 - [Study] - 27. Windows에서 Flutter로 Android 앱 개발 시작하기: 단계별 가이드 | Flutter

2024.07.23 - [Study] - 26. JavaScript 프레임워크 이해하기: React, Vue, Angular, Svelte, Ember | 웹 개발 기초

2024.07.21 - [Study] - 25. JavaScript 모듈 이해하기: 개념, 사용법 | 웹 개발 기초

 

25. JavaScript 모듈 이해하기: 개념, 사용법 | 웹 개발 기초

완벽 가이드: JavaScript 모듈 사용법과 모범 사례JavaScript 모듈의 기본 개념부터 고급 사용법까지, 모듈을 활용한 성능 최적화와 실제 프로젝트 사례를 통해 JavaScript 개발의 효율성을 높이는 방법

guguuu.com


읽어주셔서 감사합니다

공감은 힘이 됩니다

 

:)

반응형

TOP

Designed by 티스토리