플러터에서 가장 중요한 개념은 위젯이라는 개념이다
플러터에서 화면 안의 모든 요소들은 위젯이 된다
플러터의 화면 구조는 여러 위젯들이 트리 형태로 구성되어 있다
class MyWidget extends Widget{
String title; // 프로퍼티(멤버)
String description;
int count'
Widget child; // 자식 위젯
MyWidget({this.title, this.description, this.count}); // 생성자
@override
Widget build(BuildContext context){
return ...;
}
}
상태(State)는 말 그대로 어떤 상태에 대한 값을 저장하는 변수를 가리킨다
상태는 어떤 이벤트가 발생한다면 다른 상태로 바뀌게 된다
상태는 정말 다양한 방법으로 사용되는데, 로그인 여부나 찜하기 등 정말 다양한 상태가 사용된다
스트림(Stream)은 흐름이라는 뜻으로, 시간이 지남에 따라 발생하는 데이터의 흐름이라고 이해할 수 있다
데이터를 불러오는 데 시간이 오래 걸리거나, 지속적으로 데이터를 받아야 하는 경우 스트림을 통해 구현하게 된다
스트림을 통해 받는 데이터들은 언제 수신이 완료되는 지 명확히 알 수 없다는 단점이 있기 때문에 데이터를 생산하는 영역과 사용하는 영역을 구분해 구현되며, 말 그대로 '구독'해 변화를 확인할 수 있다
Container 위젯은 큰 상자처럼 위젯을 담는 역할을 하며 Padding(여백)을 설정할 수 있다
Container의 옵션
Container(
child: Text('Hello, Flutter!'),
padding: EdgeInsets.all(30),
color: Colors.blue,
height: 300,
width: 300,
)
image는 이미지를 넣기 위한 위젯이다
로컬에 저장한 이미지를 사용하기 위해선 pubspec.yaml 파일에 이미지를 등록해야 한다
또한 크기 지정 시 설정 크기와 원본의 비율이 다를 경우 원본을 지키는 쪽으로 설정된다
assets:
- images/flutter_logo.png #예시
image의 옵션
Image.asset('images/flutter_logo.png')
Image.network('https://~')
문자열을 나타낼 수 있는 위젯으로, child를 사용하지 않고 문자열을 집어넣으면 화면이 출력된다
TextStyle 위젯을 통해 문자열을 꾸밀 수 있다
TextStyle의 옵션
Text(
'Hello, Text Widget!',
style: TextStyle(
fontSize: 25,
color: Colors.purple,
fontFamily: '지정',
fontWeight: FontWeight.w700,
),
)
화면에 위젯을 배치할 때 도움을 주는 위젯으로, 플러터에는 대표적으로 Column, Row, ListView, Stack가 있다
Column은 위에서 아래로, Row는 좌에서 우로 위젯들을 배치한다
여러 위젯들을 감싸기 때문에 children을 사용한다
Column, Row의 옵션
Column이나 Row는 화면을 벗어날 만큼 많은 양의 데이터가 있으면 Buttom Overflowed가 발생한다
ListView는 많은 양의 데이터가 들어와도 스크롤이 가능한 화면을 구성하게 해준다
ListView의 옵션
ListView.builder(
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Text(
'$index' + ' Text',
style: TextStyle(fontSize: 25),
);
}
),
Stack 위젯은 위젯 위에 위젯을 쌓고 싶을 때 사용한다
좀 더 정밀하게 만들기 위해 위치를 지정할 수 있는 Positioned라는 위젯의 도움을 받기도 한다
Stack(
children: [
Image.asset('images/flutter_logo.png'),
Positioned(
left: 0,
bottom: 0,
child: Image.network(
'https://~',
width: 100,
height: 100,
),
),
],
),
Positioned 위젯으로 감싸고 leftd와 bottom값을 0으로 설정했는데, 이는 좌측 방향으로 0만큼, 하단 방향으로 0만큼 떨어지게끔 배치하라는 설정이다
플러터에는 위 버튼에 IconButton까지 총 4종류의 버튼이 존재한다
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Text 위젯만 존재
TextButton(onPressed: (){}, child: Text('Text Button'),),
Padding(padding: EdgeInsets.all(20)),
// 배경색이 칠해져 있는 상태의 버튼
ElevatedButton(onPressed: (){}, child: Text('Elevated Button'),),
Padding(padding: EdgeInsets.all(20)),
// 테두리가 그려져 있는 버튼
OutlinedButton(onPressed: (){}, child: Text('Outlined Button'),),
Padding(padding: EdgeInsets.all(20)),
// icon()을 인자로 받아 아이콘 형태의 버튼
IconButton(onPressed: (){}, icon: Icon(Icons.star),),
Padding(padding: EdgeInsets.all(20)),
],
),
),
우선 공통적으로 버튼들은 onPressed라는 프로퍼티를 가지고 있다
여기에는 함수가 인자로 들어가며, 버튼을 눌렸을 때 어떤 일을 수행할지 정의하면 된다
화면 전환은 가장 기본적인 이벤트 중 하나다
대부분의 앱은 화면이 여러개이고, 버튼 등을 눌러 해당 화면으로 이동하게 된다
모든 화면 전환 관련 이벤트는 Navigator라는 위젯을 통해 처리된다
Navigator를 활용하면 화면을 특정 화면으로 이동하거나, 이전 화면으로 돌아가는 기능을 구현할 수 있다
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => SecondScreen(),
),
);
},
child: Text('Go to Second Screen'),
),
Navigator.of(context)로 시작하는데, 이는 현재 위젯인 Scaffold 화면에서 이동하겠다는 뜻이다
여기에 Push로 화면을 쌓아 이동을 구현한다
또한 MaterialPageRoute를 통해 Navigator가 이동할 경로를 지정해준다
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Go to Second Screen'),
),
Navigator.of(context)까지는 동일하지만, .pop()으로만 끝난다
화면 클래스의 생성자를 활용해서 객체를 생성할 때 객체 내의 변수에 해당 인자 값을 저장할 수 있다
이를 활용해 화면을 이동할 때 데이터를 넘겨주는 기능을 구현할 수 있다
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => SecondScreen(
screenData: 'Data from FirstScreen',
),
),
);
},
child: Text('Go to Second Screen'),
),
final String ScreenData;
SecondScreen({required this.screenData});
// (생략)...
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('screenData : ' + screenData),
),
StatelessWidget은 위에서 계속 사용했던 위젯으로, 상태가 없는 위젯이다
제목이나 이미지와 같이 변하지 않는 위젯들은 StatelessWidget로 구현할 수 있다
StatefulWidget은 상태를 포함한 위젯이다
상태를 선언할 수 있고, 변화가 감지되었을 때 변화에 대한 이벤트를 수행한다
import 'package:flutter/material.dart';
class FirstScreen extends StatefulWidget {
State<FirstScreen> createState() => _FirstScreenState(); // 1번
}
class _FirstScreenState extends State<FirstScreen> { // 2번
void initState() { // 3번
// TODO: implement initState
super.initState();
}
Widget build(BuildContext context) { // 4번
return Scaffold(
appBar: AppBar(),
body: Center(),
);
}
void dispose() { // 5번
// TODO: implement dispose
super.dispose();
}
}
출처 : 쉽고 빠른 플러터 앱 개발