목 차
1. 플러터의 설계-컨셉
2. 플러터의 기본 위젯
3. 화면이동 이벤트
4. Stateless & Stateful
5.
플러터에서 가장 중요한 개념은 "위젯"이라는 개념입니다.
Flutter프레임워크에서는 모든 것이 '위젯'으로 조합하여 만들어진 화면으로 구성됩니다.
플러터의 화면 구조는 여러 위젯들이 트리-형태로 구성되어있습니다.
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 ...;
}
}
가장 상위 위젯으로는
'상태'를 가지는 'StatefulWidget'과 상태를 가지지 않는 'StatelessWidget'의 두가지 종류가 있습니다.
'StatelessWidget' : 말 그대로 변화가 없는 위젯,
그러므로 초기값을 지정하기만 하면 만들어지는 화면을 말합니다.
'StatefulWiget' : 계속 상태가 변화함을 의미합니다.
이 말은 화면에 표시되는 내용도 변경된다는 것과 같습니다.
각 위젯의 'Life cycle'은 다음과 같습니다.
setState는 상태변경을 트리거하고,
이에 따라서 FLutter 프레임워크가 '위젯'을 다시 빌드하도록 요청하는데 사용됩니다.
StaefulWidget'에서만 사용가능하며,
setState를 호출하면 위젯의 build메서드가 다시 호출되어 UI를 업데이트 합니다.
.
.
☆ Flutter의 setState와 React에서 사용하는 useState 비교해보기.
class _ExampleState extends State<Example> {
int count = 0;
void increment() {
setState(() {
count++;
});
}
}
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
}
didUpdateWidet'은 부모 위젯이 변경될 때 호출되는 메서드입니다.
StaefulWidget'의 부모가 새로운 구성을 전달하면 ( ex: 부모 위젯이 다시 빌드되면 )
didUpdateWidget이 호출됩니다.
이 메서드는 주로 부모 위젯에서 전달받은 새로운 구성을 처리하거나,
상태를 적절하게 업데이트하는 데 사용됩니다.
"상태(State)"는 말 그대로 어떤 상태에 대한 값을 저장하는 변수를 가리킵니다.
'State'는 어떤 이벤트가 발생한다면, 다른 상태값으로 바뀌게 됩니다.
'State'는 정말 다양한 방법으로 사용되는데, 로그인 여부나 찜하기 등 정말 다양한 상태가 사용.
스트림(Stream)은 흐름이라는 뜻으로,
시간이 지남에 따라 발생하는 데이터의 흐름이라고 이해할 수 있습니다
데이터를 불러오는 데 시간이 오래 걸리거나,
지속적으로 데이터를 받아야 하는 경우 스트림을 통해 구현하게 됩니다
스트림을 통해 받는 데이터들은 언제 수신이 완료되는 지 명확히 알 수 없다는 단점이 있기 때문에, 데이터를 생산하는 영역과 사용하는 영역을 구분해 구현되며,
말 그대로 '구독'해 변화를 확인할 수 있습니다
:: Container 위젯은 큰 상자처럼 위젯을 담는 역할을 하며 Padding(여백)을 설정 가능합니다.
EdgeInsets : 여백을 주기 위해 위젯을 사용하며 [all, froLTRB, only, symmetric ] 방식이 있습니다.
color : 상자의 배경색을 설정합니다.
width, height : 너비와 높이를 설정합니다.
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.asset : 로컬 내에 있는 이미지를 불러오는 방법.
Image.network : 인터넷의 이미지를 불러오는 방법.
width, height : 너비와 높이를 설정합니다.
Image.asset('images/flutter_logo.png')
Image.network('https://~')
문자열을 나타낼 수 있는 위젯으로, child를 사용하지 않고 문자열을 집어넣으면 화면이 출력됩니다.
TextStyle 위젯을 통해, 문자열을 꾸밀 수 있습니다.
Text(
'Hello, Text Widget!',
style: TextStyle(
fontSize: 25,
color: Colors.purple,
fontFamily: '지정',
fontWeight: FontWeight.w700,
),
)
화면에 위젯을 배치할 때 도움을 주는 위젯으로,
플러터에는 대표적으로 {Column, Row, ListView, Stack}이 있습니다.
Column은 위에서 아래로(↓), Row는 좌에서 우로(→) 위젯들을 배치합니다.
'Column'이나 'Row'는 화면을 벗어날 만큼 많은 양의 데이터가 있으면 'Button Overflowed'가 발생합니다.
'ListView'는 많은 양의 데이터가 들어와도 스크롤이 가능한 화면을 구성하게 해줍니다.
ListView.builder(
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Text(
'$index' + ' Text',
style: TextStyle(fontSize: 25),
);
}
),
Stack(
children: [
Image.asset('images/flutter_logo.png'),
Positioned(
left: 0,
bottom: 0,
child: Image.network(
'https://~',
width: 100,
height: 100,
),
),
],
),
-->> Positioned 위젯으로 감싸고, left와 bottom값을 0으로 설정했는데,
이는 좌측방향으로 0만큼, 하단 방향으로 0만큼 떨어지게끔 배치하라는 설정입니다.
:: Flutter에는 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)),
],
),
),
대부분의 앱은 여러개의 화면을 가지고, 버튼 등을 활용해 해당 화면으로 이동하게 됩니다.
모든 화면 전환 관련 이벤트는 '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)까지는 push와 비슷하지만, .pop()으로 끝나는게 다릅니다.
-> 이를 활용해, 화면을 이동할 때 데이터를 넘겨주는 기능을 구현 가능합니다.
네비게이션 로직.
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => SecondScreen(
screenData: 'Data from FirstScreen',
),
),
);
},
child: Text('Go to Second Screen'),
),
◆위 코드의 기본 구조.
: ElevatedButton은 Material Design 스타일 버튼 위젯으로, 그림자가 있는 돌출된 형태의 버튼 생성.
주요 속성.
화면 이동.
데이터 전달.
+ 'screenData' 파라미터를 통해 첫 번째 화면에서 두 번째 화면으로 데이터를 전달.
+ 'SecondScreen' 위젯은 이 데이터를 생성자를 통해 받아서 사용 가능.
.
.
SecondScreen 위젯 구현.
class SecondScreen extends StatelessWidget {
final String screenData;
const SecondScreen({Key? key, required this.screenData}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Second Screen')),
body: Center(
child: Text(screenData),
),
);
}
}
import 'package:flutter/material.dart';
class FirstScreen extends StatefulWidget {
@override
State<FirstScreen> createState() => _FirstScreenState(); // 1번
}
class _FirstScreenState extends State<FirstScreen> { // 2번
@override
void initState() { // 3번
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) { // 4번
return Scaffold(
appBar: AppBar(),
body: Center(),
);
}
@override
void dispose() { // 5번
// TODO: implement dispose
super.dispose();
}
}
createState()라는 메소드를 사용하여 Statef를 생성 합니다
StatefulWidget은 그 내부에서 사용할 State를 생성하는 것으로 그 역할을 다 합니다
State 또한 플러터 내부에서 선언된 클래스인데, 이를 상속받아FirstScreenState라는 클래스를 만들었습니다
앞에 를 붙이는 것은 관례적인 표현입니다
앞서 생성한 State를 초기화하는 단계로, 필수적이진 않습니다
super.initState()를 통해 부모 클래스의 initState() 메소드를 함께 실행합니다
StatelessWidget과 동일합니다
dispose()는 위젯이 사라질 때 실행되는 단계로, 역시 필수적이진 않습니다