앞서 플러터를 왜 해야 되는지 말씀드렸다면 이번 글에서는 플러터를 직접 구현해보며 감을 익히는것을 목표로 해보겠습니다
가장 먼저 플러터 프로젝트를 명령어로 실행하면 다음과 같이 생성된다
flutter create 'project name'
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
복잡해보이지만 다뤄야 할 코드, 즉 중점적으로 봐야할 부분은 아래의 이부분입니다.
Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
전체적인 구조로 살펴보면 Scafford 라는 형태에서 (appbar, body,floatingActionButton) 이라는 parameter 가 있고 그 값에 각각 AppBar,Center,FloatingActionButton 이라는 객체가 선언 및 생성 된것을 알 수 있습니다.
각각의 객체는 모두 위젯 입니다. 그렇다면 다음과 같은 사실을 알 수 있습니다.
1. 모든것은 위젯으로 이루어 져있다.
다 제끼고 코드를 볼때는 '( )' 부분 즉 괄호로 이루어져 있는것만 먼저 보시면 됩니다.
Scafford() 그리고 그 내부의 appbar 값에 AppBar(), body 값에 Center()
모두 결국 각 클래스( 위젯 ) 내부 그리고 그 내부에 위젯이 속하게 만들어 져 있습니다.
결국 모든것은 위젯으로 이루어 져있습니다.
2. 구성요소
Scafford 의 역할은 앱의 뼈대 역할을 합니다. 즉 아래 앱의 전체를 포괄하는 틀을 만든다고 보시면 됩니다.
그리고 appbar 는 상단 부분, 그리고 body 는 나머지 부분, floatingbutton 은 오른쪽 하단의 버튼
자 그렇다면 웹개발을 이미 했봤다라는 가정하에 설명 하도록 하겠습니다.
1. 모든 것이 위젯이다: div 태그 대신 위젯을 사용
플러터는 모든 것이 위젯으로 이루어져 있습니다. 심지어 스타일 지정해주는것 또한 위젯입니다. 웹 개발로서는 다소 충돌되는 개념인데요. 한번 에제로서 살펴 보겠습니다.
각각 웹과 flutter 의 코드 비교입니다.
웹 코드
<div style="display: flex; flex-direction: row;">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
flutter 코드
Row(
children: [
Text('Item 1'),
Text('Item 2'),
Text('Item 3'),
],
)
div 태그로 감싸듯이 Row() 클래스 안의 children 이라는 프로퍼티에 배열로서 Text() 위젯을 넣는 형태 입니다.
2. 스타일 바꾸기: style 태그 대신 Flutter 는?
CSS에서 padding, margin과 같은 속성을 사용해 여백을 설정하듯, Flutter에서는 이런 스타일도 별도의 위젯으로 감쌉니다. 예를 들어, 웹에서 <div>에 padding을 주고 싶다면 CSS에서 padding: 20px; 같은 속성을 추가하겠지만, Flutter에서는 Padding 위젯으로 감싸서 설정합니다.
Padding(
padding: EdgeInsets.all(20.0),
child: Text('Hello, Flutter!'),
)
즉 웹에서는 HTML 요소와 CSS 스타일이 분리되어 있는 반면, Flutter에서는 모든 것이 위젯입니다. 이를 웹에서의 구성 요소로 비유하자면, Flutter의 Container는 HTML의
대표적인 위젯들
1. 레이아웃 위젯
- Row: 수평 방향으로 자식 위젯을 나열하는 데 사용됩니다. mainAxisAlignment와 crossAxisAlignment 속성을 통해 정렬을 설정할 수 있어, 화면의 수평 배치를 관리하는 데 유용합니다.
- Column: 수직 방향으로 자식 위젯을 나열하는 데 사용됩니다. Row와 비슷하게 정렬 속성을 통해 배치를 조정할 수 있습니다. 예를 들어, 버튼을 세로로 나열하거나 이미지와 텍스트를 수직으로 쌓아올릴 때 Column을 사용합니다.
- Stack: 겹쳐서 배치해야 할 때 사용하는 위젯입니다. 예를 들어, 배경 이미지 위에 텍스트를 겹쳐 놓는 것처럼, 위젯을 위로 쌓아 올릴 때 사용됩니다.
- Container: 패딩, 여백, 색상, 크기, 테두리 등 스타일을 설정하는 데 많이 사용됩니다. 보통 다른 위젯을 감싸서 레이아웃을 조정하거나 스타일을 부여할 때 사용합니다.
웹 개발에서의 flex와 grid를 생각하면 됩니다. Flutter의 Row와 Column은 HTML/CSS에서 flex-direction: row와 flex-direction: column을 적용한 flex 컨테이너와 유사합니다.
예를 들어, HTML에서는 이렇게 수평 정렬을 할 것입니다:
2. 기본 위젯
기본 위젯은 UI의 기본적인 구성 요소를 나타냅니다:
Text: 텍스트를 표시합니다.
Image: 이미지를 표시합니다.
Icon: 아이콘을 표시합니다.
Button: ElevatedButton, TextButton 등 다양한 버튼 위젯이 있습니다.
레이아웃 위젯과 결합하면 다음과 같습니다.
Container(
child: Column(
children: [
Text('Welcome to Flutter'),
Image.network('https://example.com/image.jpg'),
Icon(Icons.star),
ElevatedButton(
onPressed: () {},
child: Text('Click me'),
),
],
),
)
3. GestureDetector
GestureDetector는 사용자의 제스처를 감지하고 반응하는 위젯입니다. 이 위젯을 사용하면 탭, 더블 탭, 롱 프레스, 드래그 등 다양한 사용자 상호작용을 처리할 수 있습니다 즉 태그로 치자면 onclick , onpress 이벤트를 처리한다고 보시면 됩니다.
GestureDetector(
onTap: () {
print('Widget tapped');
},
onDoubleTap: () {
print('Widget double tapped');
},
onLongPress: () {
print('Widget long pressed');
},
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Center(child: Text('Interact with me')),
),
)
4. 컴포넌트 위젯 (Card, ElevatedButton 등)
Flutter의 Card나 ElevatedButton은 웹의 <button>, <div class="card">와 같은 UI 요소로 생각할 수 있습니다. 특히 ElevatedButton은 CSS에서 box-shadow나 border-radius를 적용하여 입체감을 준 버튼과 유사합니다.
예를 들어, 웹에서 그림자가 있는 카드 컴포넌트를 만든다면 HTML과 CSS를 이렇게 작성할 수 있습니다:
<div class="card">
<p>카드 콘텐츠</p>
</div>
<style>
.card {
padding: 16px;
border-radius: 8px;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
background-color: white;
}
</style>
Flutter에서는 이와 비슷한 스타일을 Card 위젯 하나로 간단히 구성할 수 있습니다.
Card(
elevation: 4, // 그림자 크기 조정
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text('카드 콘텐츠'),
),
)
정리
- Flutter의 Row, Column은 웹의 flex 레이아웃과 비슷합니다.
- Container는 HTML의 <div> + CSS 스타일을 합친 개념으로, 여백, 패딩, 색상 등을 하나로 설정합니다.
- Flutter의 스타일은 단순 속성이 아닌 위젯으로 존재하여, 레이아웃을 위젯 트리로 구성하는 방식입니다.
- Card나 ElevatedButton 같은 Flutter의 컴포넌트 위젯은 웹의 <button>, <div class="card">와 유사한 기능을 합니다.
웹 개발자가 Flutter를 이해할 때 모든 것이 위젯으로 구성된 일관된 레이아웃 트리라는 개념을 떠올리면 훨씬 수월하게 접근할 수 있을 것입니다.
'flutter' 카테고리의 다른 글
Flutter에서 불필요한 리렌더링 줄이기: 실전 최적화 기법 (0) | 2024.11.14 |
---|---|
플러터는 왜써야 하는가?? (0) | 2024.11.08 |