๊ณต๋ถ/flutter
[Flutter] Flutter ์์
whaeun
2022. 1. 23. 23:56
๐ฅ Flutter
๐ Flutter ๊ฐ์
- ํ๋ฌํฐ ์์
- ํ๋ฌํฐ ์ค์น
- ์นด์ดํ ์ฑ ๋ง๋ค๊ธฐ
- ๋ ์ด์์ ํํ ๋ฆฌ์ผ
๐ฉ๐ฝ๐ป ๊ฐ์ ๋ด์ฉ ์ ๋ฆฌ
- ํ๋ฌํฐ(Flutter)๋?
- "dart"๋ผ๋ ์ธ์ด๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ฐ์ผ์ฉ ๊ฐ๋ฐ ํ๋ซํผ์ด๋ค.
- IOS์ Android๋ฅผ ๋ชจ๋ ํ๋ฒ์ ๊ฐ๋ฐํ ์ ์๋ ํด๋ก์ค ํ๋ซํผ์ ์ง์ํ๋ค.
- dart๋ผ๋ ์ธ์ด๋ฅผ ์ฌ์ฉํจ์ผ๋ก ๋ค์ดํฐ๋ธ ์ฑ๋ฅ์ ๋ผ ์ ์๋ค. (๋ค์ดํฐ๋ธ ์ฝ๋๋ฅผ ์ฌ์ฉํด ์๋๊ฐ ๋น ๋ฅด๋ค.)
- * flutter ์ฌ์ดํธ: https://flutter.dev
* Cross Platform์ด๋ ์ฌ๋ฌ ์ข ๋ฅ์ ์ปดํจํฐ ํ๋ซํผ์์ ๋์ํ ์ ์๋ค๋ ๊ฒ์ ๋ปํ๋ ์ฉ์ด์ด๋ค. (= ๋ฉํฐํ๋ซํผ ์ํํธ์จ์ด)
- ์นด์ดํ
์ฑ ๋ง๋ค๋ฉฐ ๊ธฐ๋ณธ ๊ตฌ์กฐ ํ์
ํ๊ธฐ
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); // st => stateless๋ฅผ ์ ํํ๋ฉด stateless ์ฝ๋๊ฐ ์์ฑ๋จ. // StatelessWidget์ ๋ฐ๋์ง ์๋ ์ ์ ์ธ ๊ฒ์ด๋ค. class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } //option + enter๋ฅผ ํตํด class ์์ฑ ๊ฐ๋ฅ // StatefulWidget์ ๋ฐ๊ฟ ์ ์๋ ๊ฒ์ด๋ค. class MyHomePage extends StatefulWidget { //๊ฐ์ ์์๊ณผ๋ ๋ค๋ฅด๊ฒ KEY key๋ผ ์ฐ๋ฉด ์ค๋ฅ๊ฐ ๋จ. - Key can't have a value of "null" (๐ฅ trouble shooting) MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { // _๊ฐ ์๋ฏธํ๋ ๊ฒ์ private๋ฅผ ์๋ฏธํจ. - ํด๋์ค ๋ด๋ถ์์๋ง ์ฌ์ฉํ๋ ๊ฒ๋ค (๋ณด์์ ์ธ ์์) int _counter = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title),), //๊ฐ์ด๋ฐ๋ก ์ ๋ ฌ body: Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('You have pushed the button this many times: '), Text('$_counter', style: Theme.of(context).textTheme.headline4) ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, // ๋์๋ง tooltip: 'Increment', child: Icon(Icons.add), ), ); } void _incrementCounter() { setState((){ _counter++; }); } }
2.1. stateless์ stateful์ ์ฐจ์ด
- stateless : ์ด์ ์ํ๋ฅผ ๊ธฐ๋กํ์ง ์์ ์์ ์ ์งํํ๋ค ์ ์์ด ๋์ด์ง ๊ฒฝ์ฐ, ์์ ์ ์๋ก์ด ์์ํด์ผ ํ๋ค.
- stateful : ์ฌ์ฉ์์ ์์ฒญ์ ์๋ฒ๊ฐ ๊ธฐ๋กํ๊ณ ์์ด ์์ ์ ์งํํ๋ค ์ ์์ด ๋์ด์ง๋๋ผ๋ ์ด์ ์ ๊ธฐ๋ก๋ ๋จ๊ณ์์ ๋ถํฐ ๋ค์ ์์ํ๋ฉด ๋๋ค.
2.2. flutter ์ ๋ ฌํ๊ธฐ - MainAxisAlignment, CrossAxisAlignment
- mainaxis๋ ์ฃผ์ถ, crossaxis๋ ํก์ถ์ ์๋ฏธํ๋ค.
- ํ์ ๊ฒฝ์ฐ main axis๋ ๊ฐ๋ก๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๊ณ cross axis๋ ์ธ๋ก๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ค.
- ์ด์ ๊ฒฝ์ฐ main axis๋ ์ธ๋ก๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๊ณ cross axis๋ ๊ฐ๋ก๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ค.
2.3. MainAxisAlignment์ CrossAxisAlignment ์์
- MainAxisAlignment
1) MainAxisAlignment.center: row์ผ ๊ฒฝ์ฐ, ๊ฐ๋ก์ถ ๊ธฐ์ค์ผ๋ก ๊ฐ์ด๋ฐ ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์ธ๋ก์ถ ๊ธฐ์ค์ผ๋ก ๊ฐ์ด๋ฐ ์ ๋ ฌ
2) MainAxisAlignment.start: row์ผ ๊ฒฝ์ฐ, ๊ฐ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์ผ์ชฝ ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์ธ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์์ชฝ์ผ๋ก ์ ๋ ฌ
3) MainAxisAlignment.end: row์ผ ๊ฒฝ์ฐ, ๊ฐ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์ค๋ฅธ์ชฝ ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์ธ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์๋์ชฝ์ผ๋ก ์ ๋ ฌ
4) MainAxisAlignment.spaceEvently: child widget ์ฌ์ด์ ์ฌ์ ๊ณต๊ฐ์ ๋ชจ๋ ๊ท ๋ฑํ๊ฒ ๋ฐฐ๋ถ
5) MainAxisAlignment.spaceBetween: child widget์ ์์๊ณผ ๋์ ๋ฐฐ์นํ๊ณ ์์ ฏ ์ฌ์ด์ ์ฌ์ ๊ณต๊ฐ์ ๋ชจ๋ ๊ท ๋ฑํ๊ฒ ๋ฐฐ๋ถ
6) MainAxisAlignment.spaceAround: ์ฒซ๋ฒ์งธ์ ๋ง์ง๋ง child ์ ๋ค์ ์ฌ์ ๊ณต๊ฐ์ ๋๋จธ์ง child์ ๊ณต๊ฐ์ ์ ๋ฐ๋งํผ ๋ฐฐ์น
- CrossAxisAlignment
1) CrossAxisAlignment.center: row์ผ ๊ฒฝ์ฐ, ๊ฐ๋ก์ถ ๊ธฐ์ค์ผ๋ก ๊ฐ์ด๋ฐ ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์ธ๋ก์ถ ๊ธฐ์ค์ผ๋ก ๊ฐ์ด๋ฐ ์ ๋ ฌ
2) CrossAxisAlignment.start: row์ผ ๊ฒฝ์ฐ, ๊ฐ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์์ชฝ ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์ธ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์ผ์ชฝ ์ ๋ ฌ
3) CrossAxisAlignment.end: row์ผ ๊ฒฝ์ฐ, ๊ฐ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์๋๋ก ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์ธ๋ก์ถ ๊ธฐ์ค์ผ๋ก ์ค๋ฅธ์ชฝ ์ ๋ ฌ
4) CrossAxisAlignment.stretch: ์ข์ฐ๋ฅผ ๊ฝ์ฐจ๊ฒ ๋ฐฐ์น 5) CrossAxisAlignment.baseline: row์ผ ๊ฒฝ์ฐ, ์ํ ์ ๋ ฌ / column์ ๊ฒฝ์ฐ, ์์ง ์ ๋ ฌ
2.4. ๋ ์ด์์ ๋ฐฐ์น์ ๋ฐ์ํ ์ฑ ์ฐ์ต
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
//๐ฅ trouble shooting - type 'MyApp' is not a subtype of type 'StatelessWidget'"
// https://stackoverflow.com/questions/51334839/another-exception-was-thrown-type-myapp-is-not-a-subtype-of-type-statelesswi
// MyApp์ ๋ณ๊ฒฝํ ๊ฒฝ์ฐ restart ํด์ผ ํจ.
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isStared = true;
int _count = 41;
@override
Widget build(BuildContext context) {
//MainAxisAlignment์ CrossAxisAlignment๋ก ์ ๋ ฌํ ์ ์๋ค.
var titleSection = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Cat is so cute.',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 26)),
Text('This is layout practice.',
style: TextStyle(color: Colors.grey, fontSize: 26)),
],
),
//padding ์ค์
Padding(padding: EdgeInsets.all(10.0),),
//Icon์ ํฌ๊ธฐ ์ค์ ๊ฐ๋ฅ
//์ผํญ ์ฐ์ฐ์ ์ฌ์ฉ Bool ? A : B
IconButton(
onPressed: _pressedStar,
//icon button ์์ icon์ด ๋ค์ด๊ฐ๋ ํ์
icon: (_isStared ? Icon(Icons.star) : Icon(Icons.star_border)),
color: Colors.deepOrange,),
Text('$_count', style: TextStyle(fontSize: 30),)
],
);
var buttonSection = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Icon(Icons.call, size: 30, color: Colors.lightBlue,),
Text("CALL", style: TextStyle(color: Colors.lightBlue),)],
),
Padding(padding: EdgeInsets.all(40.0),),
Column(children: <Widget>[
Icon(Icons.near_me, size: 30, color: Colors.lightBlue,),
Text("ROUTE", style: TextStyle(color: Colors.lightBlue),)],
),
Padding(padding: EdgeInsets.all(40.0),),
Column(children: <Widget>[
Icon(Icons.share, size: 30, color: Colors.lightBlue,),
Text("SHARE", style: TextStyle(color: Colors.lightBlue),)],
),
],
);
// Container์ padding์ ๋ฃ์ ๊ฒฝ์ฐ, ์ ์๋ ์ ์์ ๋ค ๋ค์ด๊ฐ๋ค.
var textSection = Container(
child: Text(
"The cat (Felis catus) is a domestic species of a small carnivorous mammal."
" It is the only domesticated species in the family Felidae and "
"is often referred to as the domestic cat to distinguish it from the wild "
"members of the family. A cat can either be a house cat, a farm cat or"
" a feral cat; the latter ranges freely and avoids human contact."
" Domestic cats are valued by humans for companionship and their ability to"
" kill rodents. About 60 cat breeds are recognized by various cat registries.",
style: TextStyle(fontSize: 15)),
padding: EdgeInsets.all(20.0),
);
return Scaffold(
body: Column(
//์ธ๋ถ ๋งํฌ๋ก๋ถํฐ ์ฌ์ง์ ๋ฐ์์์ ํ์ํ๋ ๊ฒ์ network๋ก ์ํํ๋ค.
children: <Widget>[
Image.network("https://user-images.githubusercontent.com/61380136/150347579-6cd5462e-0a75-467a-a0f2-2dd9c16d3744.png",
height: 240, width: 600, fit: BoxFit.cover,),
Padding(padding: EdgeInsets.all(10.0),),
titleSection,
Padding(padding: EdgeInsets.all(1.0),),
buttonSection,
//Padding(padding: EdgeInsets.all(1.0),),
textSection,
],
),
);
}
void _pressedStar() {
setState(() {
if (_isStared){
_isStared = false;
_count -= 1;
} else{
_isStared = true;
_count += 1;
}
});
}
}
- ์คํ ํ๋ฉด
๐ฅ Trouble Shooting ๐ฅ
- Ctrl + Space ํด๋ ์ด๋ค ์์ฑ์ ์ฌ์ฉํ ์ ์๋์ง ์๋จ๊ณ Spot light๊ฐ ๋จ๋ ๋ฌธ์
=> ํ๊ฒฝ ์ค์ ์์ ํด๋น ๋จ์ถํค๋ฅผ ๋ณ๊ฒฝํ๋ค. - Key can't have a value of "null"
=> ์ค๋ฅ ๋ฐ์ ์์ธ: null safety๊ฐ ํ์ฑํ๋์๊ธฐ ๋๋ฌธ์ด๋ค. null์ด ๋ ์ ์๋ ๋งค๊ฐ๋ณ์๋ ํค๊ฐ null ๊ฐ์ ๊ฐ์ง์ง ์๋๋ก ํ๋ค.
=> ํด๊ฒฐ๋ฐฉ๋ฒ: null์ด ๋ค์ด๊ฐ ์ ์์์ ๋ํ๋ด๋๋ก ํ๋ ?์ ๊ฐ์ด ๊ผญ ๋ค์ด๊ฐ์ผ ํ๋ค๊ณ ํ์ํด์ผ ํ๋ required๋ฅผ ์ฌ์ฉํ์ฌ error๋ฅผ ํด๊ฒฐํ๋ค.
# ํด๋น ์ค๋ฅ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ค์ํ ๋ฐฉ๋ฒ
1) required:
2) Default value:
3) Nullable parameter:
4) Positional parameters: