어떤 코드든지 최대한 재사용성 있고 가독성 좋게 코드를 작성해야 협업에서도 그렇고 유지보수 측면에서도 훨씬 간편해지므로 항상 DRY나 프로젝트 Architecture를 통해 구성하여야 한다. 기본문법과 Lifecycle, 다양한 매개변수들을 사용하며 최대한 효율적이고 가독성 좋은 코드를 작성할 수 있도록 하자
🍕 DRY(Do not Repeat Yourself): 반복하지 마라는 뜻으로 중복코드 작성을 지양하라는 말이다.
row: 행, column열, axis 조절을 통해서 각 행과 열에서의 child 위치를 지정할 수 있고, childeren을 사용해서 자식 위젯을 리스트 형식으로 여러개 받을 수 있다.
return Scaffold(
body: Column(
children: [
childWidget
],
),
);
mainAxisAlignment: 주축
crossAxisAlignment: 반대축
특별한 제한사항이 없다면 Row위젯과 Column위젯의 주축은 디스플레이만큼의 크기(parent)를 차지하고 반대축은 위젯만큼의 크기(chide)를 차지한다.
stless, stful, stanim을 입력하면 각 특성에 맞는 위젯 틀을 빠르게 구현하여 개발자는 해당 위젯이름만 입력하면 된다.
기본적으로 투명색이라 패딩 대신 사용하면 개발자 코드 가독성 향상 및 const에서 padding보다 성능향상이 된다.
default는 true로 현재 이 앱이 디버그 상태라는 것을 알려주는 flag를 우측 상단에 표시한다. false로 선언하면 debug flag를 없앨 수 있다.
확장형 위젯 flex로 화면에서 차지하는 비율을 조절할 수 있다.
Flexible widget을 상속받고 있는데 Flexible widget으로 하게되는 경우 fit: FlexFit으로 flex와 동일한 효과를 얻을 수 있다.
FlexFit의 경우에는 실제로 Flexible위젯이 차지할 수 있는 공간만큼 자식 위젯이 차지하게 할 것인지 아닌지 설정하는 것으로 tight를 사용하면 Flexible이 차지하는 만큼, 아니라면 loose를 사용해서 사용자가 선택한 크기만큼 적용할 수 있다.
Flutter에서 패딩은 EdgeInsets이라는 EdgeInsetsGeometry를 상속받는 클래스를 통해 구현 가능하다. 딱 4가지만 알면 padding은 전부 사용가능하다고 봐도 무방하다.
1. all(value): 위, 아래, 왼쪽, 오른쪽 모두 동일하게 여백을 추가
2. symmetry(vertical: value, horizontal: value,): vertical(수직), horizontal(수평)에 각각 여백을 추가할 수 있다. 위젯기준 위아래에 추가되는게 vertical 양옆에 추가되는게 horizontal이다.
3. only(top, bottom, left, right): 4개의 면에 직접 값을 세팅해줄 수 있다.
4. fromLTRB: only와 마찬가지로 각 면에 세팅할 수 있지만 순서대로 값만 넣어주면 되기에 only와 달리 parameter변수를 선언할 필요가 없어서 간편하지만 직관적이지 않다.
시멘틱버전관리란 소프트웨어 버전 관리에 표준화된 규칙이다.
major.minor.patch로 구분되어 있고, 간단하게 큰 변화 - 주로 호환성 변화, 기존 호환성이 유지되면서 기능이 추가 및 삭제될때, 기존 기능에서 버그를 수정할때 라고 볼 수 있다. 맨 앞자리가 바뀌지 전까진 항상 같은 버전내에선 모두 호환이 되어야 하므로 잘 지켜줘야할 필요성이 있다.
따라서 Major 버전 업데이트가 아니라면 패키지의 사용방법이 변하지 않는다고 봐도 무방. 이때 major 버전을 제외한 모든 버전을 가장 최신의 버전을 사용하라는 것을 ^(caret)을 사용해서 나타낸다. ^x.x.x 이 caret이 있어야 major 버전이 변경되기 전까지 자동으로 최신버전으로 업데이트가 가능하므로 외부라이브러리 패키지를 사용할때 명시해주는것이 좋다.
Scaffold안에서 appBar parameter에 AppBar를 생성해서 넣어주면 된다. centerTitle을 true로 설정하면 기본적으로 좌측정렬되는 Title도 중앙정렬된다. actions를 줄수도 있는데 우측부터 나열되며 icon을 설정할 수 있고 거기에 onPress callback을 받아서 처리가 가능하다.
pub.dev에서 webview 라이브러리를 import하여 사용하였다. controller를 통해 webview에 띄울 화면을 Uri로 설정할 수 있고 onPress와 함께 사용하여 특정 icon 클릭 시 화면 전환또한 가능하다.
🍕 Android와 IOS에서 각 플랫폼별 구동방식이 약간의 차이가 있는데 WebView에서 동영상을 지원하려면 JavascriptMode가 되어야 한다. IOS는 기본으로 되어 있지만 Android는 따로 설정을 해주어야 한다. .setJavaScriptMode(JavaScriptMode.unrestricted)
제스처를 감지하는 위젯으로 GestureDetecctor로 감싼 모든 위젯에 적용이 가능하며 onTap, onDoubleTap, onLongPress, onPanUpdate등 다양한 제스처 이벤트를 지원한다.
pub.dev 라는 사이트를 들어가보면 flutter에서 사용할 수 있는 패키지들을 모아 놓은 공식 패키지 저장소이다. 물론 이거 외에도 서드파티 라이브러리들을 설정해서 사용가능하다.
사용할 때는 pub points와 likes가 높은 것을 선택하는 것이 좋지만 상황에 따라서 사용하면 된다. 여기서는 hugopassos.dev라는 인증마크가 달린 개발자가 개발하였고 현재 0.6.2버전을 약 1년전에 업데이트했다. BSD-2-Clause 오픈 소스 라이센스로 사용, 수정, 배포가 허용되지만 라이선스 고지 및 책임 면책 조항이 부여되어 있으며 상용소스로 사용이 가능하다. Dart3 compatible로 Dart3에서 원활히 작동한다고 나와있다.

Likes: 좋아요 개수라고 보면 된다.
PUB POINTS: 패키지 유지관리자가 Dart Anlayze 규칙을 얼마나 잘 따르고 있는 지를 측정하는 지표로 문서화(README, 패키지문서), 형식 및 규칙 준수(코드 스타일, 분석기 경고 처리 여부 등) , 단위 테스트 및 통합 테스트 존재여부 등을 뜻한다.
POPULARITY: 해당 패키지가 실제로 얼마나 많이 사용되는지를 나타내며 주로 패키지 다운로드 수와 사용 빈도를 기반으로 나온다. 따라서 실제 사용 빈도와 다운로드수를 반영한 인기지표를 나타낸다.

이전에 assets을 추가했던 것 처럼 패키지 또한 pubspec.yaml에 추가해주면 되는데 title옆의 복사버튼을 누르게 되면 적용할 패키지가 복사되는데 이걸 예상했듯이 pubspec.yaml문서 안의 dependencies안에다가 yaml파일이니 들여쓰기를 두칸해서 flutter와 맞춰주고 적용해주면된다.

이후 문서에서 android나 ios등 개별 플랫폼에서 설정해야 하는 세팅이 있는지 확인하고 있다면 설정해주면된다.
Flutter의 가장 큰 모토는 "Everything is a Widget"이다. 화면에 보여지는 모든 요소를 클래스로 표현하며 이를 위젯이라고 부른다. UI를 표현하는 위젯은 크게 두 가지로 나뉜다: StatelessWidget과 StatefulWidget.
기본적으로 Flutter의 위젯은 불변(immutable)이다. 즉, 위젯의 상태가 변경되어야 하는 경우, 기존 위젯이 업데이트되는 것이 아니라 새로운 상태를 반영한 새로운 위젯이 생성되고 기존 위젯을 대체한다. 이 과정은 Flutter의 효율적인 UI 업데이트 시스템인 "위젯 트리"를 통해 관리된다.
StatelessWidget은 상태를 가지지 않는 위젯이다. 이 위젯은 한 번 생성되면 이후 변경되지 않으며, 주로 고정된 UI 요소를 표현할 때 사용된다. 예를 들어, 텍스트, 아이콘, 고정된 레이아웃 등이 StatelessWidget으로 구현된다. 상태 변화가 필요 없는 UI 구성 요소를 나타낼 때 적합하다.
사용 예시:
class MyStatelessWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Text('이 위젯은 변하지 않는 텍스트를 표시합니다.');
}
}
위 예제에서 MyStatelessWidget은 고정된 텍스트를 표시하며, 어떤 상태 변화도 반영하지 않는다. 상태나 UI가 변하지 않는다는 점에서, StatelessWidget은 효율적이고 간단하다.
StatelessWidget은 상태가 없는 위젯이기 때문에 라이프사이클이 상대적으로 단순하다. StatelessWidget의 생명 주기는 다음과 같다:
| 단계 | 설명 |
|---|---|
| 생성자 호출 (Constructor) | 위젯이 처음 생성될 때 호출된다. StatelessWidget은 초기 상태를 가지지 않기 때문에 이 단계에서 대부분의 설정이 이루어진다. |
| build() 호출 | 위젯이 화면에 그려질 때 호출된다. 이 메서드는 위젯이 UI 트리에 추가될 때마다 호출되며, 이 과정에서 위젯의 외관을 정의한다. StatelessWidget은 상태 변화가 없으므로, build() 메서드가 반복적으로 호출될 이유가 없다. |
StatelessWidget의 라이프사이클은 이 두 단계가 전부다. 한 번 그려진 후 상태 변경이 없으므로 다시 빌드되지 않는다.
StatefulWidget은 상태를 가질 수 있는 위젯이다. 상태가 변경됨에 따라 UI가 동적으로 변해야 하는 경우 StatefulWidget을 사용한다. 예를 들어, 버튼을 클릭할 때 UI가 업데이트되거나, 입력 폼의 값이 변경되는 경우 등이 이에 해당된다.
StatefulWidget은 두 개의 클래스가 함께 사용된다:
StatefulWidget 클래스: 이 클래스는 위젯의 불변 부분을 정의하며, 실제 상태는 관리하지 않는다.
State 클래스: 이 클래스가 실제 상태를 관리하며, UI를 업데이트하는 로직을 포함한다.
사용 예시:
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int counter = 0;
void _incrementCounter() {
setState(() {
counter++;
});
}
Widget build(BuildContext context) {
return Column(
children: [
Text('Counter: $counter'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
);
}
}
위 예제에서 StatefulWidget은 클릭할 때마다 카운터 값이 증가하며, 이 상태 변화에 따라 UI가 다시 그려진다. 상태를 변경할 때는 setState를 호출해 Flutter에게 UI를 다시 Build해야 함을 알린다.
이 Build부분이 중요한데 실제로 값은 변경되더라도 widget은 불변이기 때문에 build를 통해 다시 그려주어야 실제 변경된 값으로 widget또한 변경되기 때문이다.
🍕 setState가 불리기만 하면 변경된 값이 있는 경우 그 값이 전달되어 굳이 setState안에 변경되는 값을 안 넣어도 되지만 넣어주는 게 가독성이 좋고 직관적이므로 State변경 시 적용될 변수는 setState안에 넣어주도록 하자.
StatefulWidget은 상태를 관리할 수 있기 때문에, 더 복잡한 라이프사이클을 가진다. 이 라이프사이클은 상태 초기화, 상태 변경, 위젯의 재구성 등의 과정에서 중요한 역할을 한다. 주요 단계는 다음과 같다:
| StatefulWidget 단계 | 설명 |
|---|---|
| Constructor | StatefulWidget이 생성될 때 호출됨. 초기 상태나 필수 데이터를 전달할 때 사용됨. |
| createState() | StatefulWidget이 처음 생성될 때 호출됨. 위젯의 상태를 관리하는 State 객체를 생성. 이 메서드는 한 번만 호출됨. |
위는 widget, 아래는 해당 widget에 설정되는 State에 대한 설명이다.
| State 단계 | 설명 |
|---|---|
| initState() | State 객체가 처음 생성될 때 호출됨. 상태 초기화가 필요하다면 이 단계에서 설정함. 예를 들어, API 호출이나 애니메이션 초기화 작업이 여기서 이루어짐. super.initState()를 반드시 호출해야 함. |
| didChangeDependencies() | initState() 다음에 호출되며, 이 메서드는 InheritedWidget이나 다른 종속성이 변경되었을 때 호출됨. 주로 종속성을 업데이트하거나 초기 데이터에 접근할 때 사용됨. |
| build() 전 - dirty 상태 | build()가 호출되기 전, 위젯이 다시 렌더링될 필요가 있을 때 위젯은 "dirty" 상태로 표시됨. 이는 Flutter가 해당 위젯을 재구성해야 함을 인지하게 함. |
| build() | 위젯의 UI를 그리는 메서드로, 상태가 변경될 때마다 호출됨. 이 단계에서는 위젯이 "dirty" 상태로 표시되고, UI를 렌더링한 후 "clean" 상태로 전환됨. |
| build() 후 - clean 상태 | build()가 완료된 후, 위젯은 "clean" 상태가 됨. 이 상태에서는 위젯이 정상적으로 렌더링되었음을 의미하며, 더 이상 재구성이 필요하지 않음. |
| didUpdateWidget() | 부모 위젯이 변경되거나 새 데이터를 전달받았을 때 호출됨. 이전 위젯과 현재 위젯을 비교해 필요한 업데이트를 수행함. |
| setState() | 위젯의 상태가 변경될 때 호출되며, 변경된 상태에 따라 UI를 다시 빌드함. 이 단계에서 위젯이 다시 "dirty" 상태가 됨. |
| deactivate() | 위젯이 트리에서 제거될 때 호출됨. 이 단계에서는 위젯이 트리에서 제거될 준비가 됨. 위젯이 재구성될 때 잠시 제거되었다가 다시 추가될 수 있음. |
| dispose() | 위젯이 완전히 트리에서 제거되기 전에 호출됨. 리소스 해제, 컨트롤러 및 애니메이션 해제 작업이 여기서 이루어짐. 이 메서드가 호출되면 해당 State 객체는 더 이상 재사용되지 않음. |
setState의 경우에는 clean후에 다시 dirty - build - clean의 반복으로 계속해서 사이클이 돌아가게 된다.
didUpdateWidget의 경우 부모 위젯이 변경되면 자연스레 자식 위젯또한 변경되게 된다. 따라서 다시 생성자(Constructor)를 widget에서 실행하게되는데 이미 생성된 이력이 있으므로 createState를 부르지 않고 이미 생성된 widget을 찾아서 state와 연동한다. 그러면 다시 dirty부터 시작해서 진행하게 된다.
초기화 작업은 initState()에서, 자원을 해제하는 작업은 dispose()에서 처리하는 것이 적절하다.