반응형

플러터 프로젝트 구조

 

1. 프로젝트 폴더 구성

플러터 프로젝트를 생성하면 위와 같이 여러 폴더와 파일이 생성되어 있다.

lib 폴더에 플러터 앱의 소스가 작성된 main.dar 파일이 있다. 그리고 android, ios, linux, macos, windows 폴더에는 각 운영체제에서 프로젝트를 시작할 때 필요한 파일이 있다. 그리고 test 폴더에는 다트 코드로 함수를 테스트할 때 사용하는 파일이 있다. 많은 파일과 폴더가 있지만 핵심적인 폴더는 lib 폴더이므로 플러터 공부를 처음 시작할 때에는 우선 lib 폴더에 집중하면 된다. 그리고 루트 경로에서 주목할 파일은 pubspec.yaml 파일인데 이 파일은 플러터에서 다양한 패키지, 폰트, 이미지 등을 사용할 수 있게 해주므로 앱을 꾸미는데 많이 사용하는 파일이다.

주요 폴더와 파일을 요약해서 정리하면 아래와 같다.

폴더 / 파일 내용 비고
android 폴더 안드로이드 프로젝트 관련 파일 안드로이드 스튜디오로 실행 가능
ios 폴더 iOS 프로젝트 관련 파일 XCode로 실행 가능(Mac OS만 가능)
lib 폴더 플러터 앱 개발을 위한 dart 소스 코드 파일  
test 폴더 플러터 앱 개발 중 테스트 파일  
pubspec.yaml 패키지, 이미지, 폰트 설정 직접 관리
README.md 프로젝트 소개
.gitignore git에 커밋, 푸시할 때 무시할 파일 기록
.metadada Flutter SDK 정보 자동 관리
.packages Flutter SDK에 사용하는 기본 패키지 경로
first_flutter_app.iml 파일이 자동으로 생성될 때 만들어지는 폴더 위치
pubspec.lock pubspec.yaml 파일에 적용된 패키지 위치

 

2. 플러터 메인 소스 구성

필자는 간단하게 Hello World!를 화면 상에 출력하는 코드를 아래와 같이 작성해 보았다.

1) import 구문

소스 첫 줄을 보면 import 구문이 있다. import는 자바나 파이썬의 import와 같이 다른 클래스나 패키지를 불러올 때 사용하는 구문이다.

위 코드에서는 material.dart 패키지를 불러왔는데 이 패키지는 플러터의 UI와 관련된 거의 대부분의 클래스가 포함되어 있어서 자주 보게 될 것이다.

 

2) main() 함수

플러터도 다른 언어들과 동일하게 main() 함수에서 시작하는데, 위 코드의 main() 함수에서는 runApp() 함수를 호출하면서 App이라는 위젯을 전달한다.

 

3) App 클래스

앱에서 위젯은 클래스로 구현한다. 위 코드를 보면 첫 줄의 'class App extends StatelessWidget'에서는 App 클래스를 정의하였는데 클래스 이름 뒤의 extends는 상속을 의미하는 키워드이다. 이 코드에서는 StatelessWidget이라는 클래스를 상속받았는데 상태가 변경되지 않는 위젯을 상속받았다고 생각하면 편하다. 다음 줄에서는 @override 어노테이션을 사용해서 build()라는 함수를 오버라이딩(재정의)했다. 플러터를 실행하고 난 후 main() 함수에서 runApp() 함수를 호출해서 App 위젯을 전달하여 App 클래스를 실행하면 MaterialApp() 함수를 반환해야 하는데 빈 도화지, 빈 캔버스의 역할을 한다고 생각하면 편하다. 이 함수에는 title, home, appBar, body 등이 정의되어 있다.

 

3. Stateless / Stateful

https://itnext.io/stateless-vs-stateful-cde9d178084f

플러터 앱을 구성하는 위젯은 stateless와 stateful 두 가지로 구분한다.

 

1) Stateless Widget

먼저 stateless widget은 상태를 연결할 필요가 없는 위젯인데, 쉽게 말하면 어떤 위젯을 불러와서 내용을 새롭게 갱신할 필요가 없어서 정적인 화면을 보여줄 때 사용하는 위젯이다. 이 위젯은 StatelessWidget 클래스를 상속받아서 만든다. 이러한 stateless widget은 화면이 정적이므로 메모리와 같은 자원을 적게 사용하면서 화면을 구성할 수 있다.

 

2) Stateful Widget

계산기 앱을 만든다고 가정해보자. 숫자를 입력하고 계산 버튼을 누르면 결괏값이 출력되는데, 버튼을 누를 때마다 새로운 결괏값이 반영되야 한다. 즉, 앱이 위젯의 상태를 계속 감시하다가 특정 상태에 충족하면 알맞은 처리를 수행해야 하는데 이와 같이 상태가 연결된 동적인 위젯을 stateful widget이라고 하며 이 위젯은 StatefulWidget 클래스를 상속받아서 만든다. 이러한 stateful widget은 상태가 변경되면 동적인 처리를 할 수 있도록 계속 위젯의 상태를 감시해야 하므로 메모리와 같은 자원을 많이 소비한다.

 

4. 플러터 메인 소스 심화

2. 에서는 플러터 메인 소스 파일의 구성을 살펴 보았는데 이번에는 직접 수정해보면서 메인 소스 파일의 구조를 이해해 보고자 한다.

 

1) Material 앱 내부의 코드를 싹 다 지우고 home: Text('Hello World!')만 입력하고 앱을 실행해보기

배경은 검은색이고 글자는 빨간색 그 밑에 노란색 밑줄이 그어진 채로 화면이 표시되었다.

처음에 필자가 구현한 코드를 실행했을 때와 다르게 왜 이러한 상태로 출력된 것일까? 그 이유는 기본적인 화면 구성을 호출하지 않고 home에 Text() 함수를 바로 넣어서 기본 테마가 적용되지 않았기 때문이다.

 

2) 화면의 정가운데에 배치하기

필자는 이미 구현한 코드에서 Hello World!를 화면의 정가운데에 배치 했었는데 이를 위해서는 Center로 감싸주면 된다.

Center() 함수를 호출하고 child 옵션에 Text() 함수를 넣으면 된다. 본 코드에서는 Center() 함수에 Text() 함수를 하나만 넣어서 child 옵션을 사용한 것인데, 여러 위젯을 넣을 때는 children 옵션을 사용하면 된다.

이 코드의 실행 결과는 다음과 같다.

 

3. 앱 타이틀 구현하기

검은 배경에 빨간 글씨, 너무 섬뜩하다. 그리고 앱인데도 불구하고 앱 바, 즉 앱의 타이틀 부분이 없다.

플러터 앱을 개발할 때는 규칙이 있는데 바로 화면이 scaffold라는 것을 가져야 한다는 것이다. scaffold는 토익을 공부하다 보면 비계라는 뜻을 가진 단어로 많이 등장하는데 이러한 뜻과 같이 화면의 구조를 제공해주는 역할을 한다.

scaffold는 navigation bar, bottom tab bar, app bar 등을 구현할 수 있도록 해준다.

위와 같이 home을 Scaffold로 묶어주고 그 안에 appBar와 body 옵션을 넣어주면 제일 처음과 같이 구현이 끝난다.

 

4. Stateful 화면 구성해보기 with 스위치

위와 같은 코드를 작성하면 앱에 스위치가 생긴다. 하지만 현재는 StatelessWidget을 상속 받았기 때문에 스위치를 눌러도 화면에 변화가 없다. 이를 위해서 Stateful 위젯으로 바꿔보자.

코드가 복잡해졌지만 전체적인 구조를 중심으로 살펴보자.

Stateful widget은 Stateless widget과는 다르게 혼자서 화면을 출력할 수 없고 State 클래스가 필요하다.

그래서 State 클래스를 상속받는 _App 클래스를 만들고 그 안에 만들어 놓은 위젯을 담는다. 그리고 StatefulWidget 클래스를 상속받는 App은 createState() 함수를 오버라이딩해서 호출하면 MyApp 클래스가 현재 화면을 감시하고 있다가 상태가 변경되면 이를 감지하고 _App 클래스가 화면을 갱신한다.

위와 같이 print() 함수를 통해 찍힌 결과를 보면 상태가 잘 바뀜을 확인할 수 있지만 여전히 화면은 그대로다. 그 이유는 변숫값이 바뀌었는데 앱은 그 사실을 모르고 있기 때문에 setState() 함수를 통해 앱에도 이 사실을 알려 화면을 갱신해야 한다.

이렇게 수정하고 나면 이제 스위치를 누를 때마다 onChanged 이벤트가 발생하면서 value 값을 전달받고 이 값이 switchValue에 담기고 이 값이 가리키는 Switch의 값이 변경되면서 화면을 갱신하여 잘 바뀌는 것을 확인할 수 있다.

'Flutter with dart' 카테고리의 다른 글

[Flutter] WebView 위젯  (0) 2023.09.25
[Flutter] 위젯 UI 배치 연습  (0) 2023.09.24
[Flutter] 플러터 위젯 정리  (0) 2023.09.24
[dart] dart(다트) - List 타입  (0) 2023.06.22
[dart] dart(다트) - 기초 문법  (0) 2023.06.22