Flutter란?
dart란?
구글이 JS를 대체하기 위해 개발한 웹프로그래밍 언어로 모바일 앱,웹,앱, 명령어 스크립트, 서버 프로그래밍 등 dart를 사용해 만들수있다.
웹앱이 아닌 네이티브 코드로 안드로이드 / IOS용 앱을 동시에 개발이 가능하다.
모든것들이 전부 Object로 취급된다.
:var 선언할수있는 것들 전부, function, number, null 전부 Object로 취급된다.
변수에 넣을 수 있는 모든 것은 객체이며 모든 객체는 클래스의 인스턴스로 취급된다.
List , List같이 제너릭 type을 지원한다.
Typed언어이지만 자유도를 주며 Dynamic은 any같이 기본 오브젝트를 명시적으로 타입 지정해준다.
public private protected의 정의가 없으며, _function()으로 정의된다.
문법적으로는
print();로 출력이 가능하고
data type으로는 number , double , String, bool, List, Map(key:value)로 나뉜다.
그리고 var는 타입을 써주지않고 처음 선언한 값이 데이터타입이 된다.
그리고 final과 const는 같지만 조금은 다르다.
Flutter설치
- 1.flutter SDK다운
2.android studio 설치
3.환경변수 등록
4.등등
/usr/local/Caskroom/flutter/2.10.3/flutter- brew를 통해서 설치해준다.
: 패키지를 통해서 데스크탑에 설치하게되면 버전 업데이트의 번거로움이 생긴다.- brew install flutter /
brew install android-sdk /
brew install android-ndk /
brew install android-studio
brew tap dart-lang/dart
brew install dart- android-studio는 패캐지로 설치한다.
- android-studio에서 flutter와 dart를 이용하여 앱을 만든다.
Flutter구조
- ios: iOS 빌드시에 필요한 파일들과 코드들이 생성됩니다.
android: Android 빌드시에 필요한 파일들과 코드들이 생성됩니다.
lib: 스켈레톤 앱의 코드가 들어있으며, 이후의 코드 구현은 거의 모두 이 폴더 내에서 합니다.
pubspec.yaml: 플러터 프로젝트의 중심 같은 파일로, 앱 이름, 버전, 빌드, 의존성 (dependencies), 리소스 (이미지, 폰트 파일 등) 등이 모두 등록되어 있는 파일입니다.
StatelessWidget 클래스
: 상태가 없는 위젯을 정의하는데 사용된다.
상태를 가지지 않는 위젯을 구성하는 기본 클레스로 한번 그려진다음 다시 그리지 않는다는 뜻이다.
이러한 클래스는 상수는 가질수 있지만, 프로퍼티로 변수를 가지지않는다.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
theme:ThemeData(primarySwatch:Colors.blue,
home: Scaffold( ··· );
),
);
}
}
Stateful 클래스
: 상태가 있는 위젯을 정의하는데 사용된다.
생명주기동안 값이 변할수있는 위젯으로 반드시 State인스턴스를 생성하는 statefulWidget클래스를 생성해야된다. 자체 값은 변하지 않지만, 내부의 state클래스가 생명주기동안 값이 변한다.
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ···,
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
여기에서 setState()는 전달된 익명 함수를 실행한 후 화면을 다시 그리게 하는 build()메소드를 다시 실행시키는 역할을 한다. setState()메소드는 상속 받고 있는 state 클래스가 제공하는 메소드이다.
Flutter LifeCycle
statefulWidget을 만들때, state객체를 만든다. 해당 위젯의 모든 가변 상태가 유지되는곳이다.
: state는 재구축할때마다 폐기되지않고 프레임이 재구성 될때 마다 state속성, getter, settet등에서 가져온다.
createState()
: 빌드하도록 지시하면 즉시 호출되고 이 메소드는 반드시 존재해야 한다.
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
mounted == true
: createState가 state클래스를 생성하면 buildContext는 state에 할당된다.
모든 위젯은 bool형식의 this.mounted속성을 가지고있다.(setState()를 쓸때 유용하다)
initState()
: 위젯이 생성될때 처음으로 호출되는 메소드이다. 오직 한번만 호출된다. super.initState()를 호출해야된다.
@override
initState() {
// 부모의 initState호출
super.initState();
// 이 클래스애 리스너 추가
cartItemStream.listen((data) {
_updateWidget(data);
});
}s
didChangeDependencies()
: 위젯이 최초 생설될때 initState다음에 바로 호출된다.
의존 데이터 객체가 호출될때마다 호출된다.(API호출의 경우)
build()
: 반드시 위젯을 리턴하고 플루터의 모든 gui는 child / children을 가진 위젯이다.
didUpdateWidget()
: 부모 위젯이 변경되어 이 위젯을 재 구성해야 되는 경우 일부 데이터들과 state들을 재정의 해주거나 초기화 해주는경우에 사용된다.
@override
void didUpdateWidget(Widget oldWidget) {
if (oldWidget.importantProperty != widget.importantProperty) {
_init();
}
}
setState()
: build context의 위젯을 다시 빈드하게되고 비동기적이지 않은 callback을 사용한다.
deactivate()
: 거의 사용되지않지만, 트리에서 state가 제거될때 호출된다.
void updateProfile(String name) {
setState(() => this.name = name);
}
dispose()
: state객체가 영구히 제거된다.
mounted == false
: 이 상태에서 state객체는 다시 mount되지 않고, setState()가 호출되면 에러가 발생한다.
dart 문법
Row 안에 컨테이너박스 2개를 넣을수있다.
body: Row(
children:[
Flexible(child: Container( width: )),
Container()
]
)
children:[
Flexible(child: Container(color: Colors.blue ), flex: 3,),
Flexible(child: Container(color: Colors.green ), flex: 7,),
]
//=>이런식으로 css를 줄수있고 박스 2개를 3:7로 나눈다.
children:[
Expanded(child: Container(color: Colors.blue )),
Container(width: 100, color: Colors.green ),
]
//=>Expanded는 flex:1을 가진박스랑 똑같다.
변수
int
Double
Num
Bool
String
List
Set
Map
dynamic
dynamic some =9;
some = 'apple'
ㄴ> 다이나믹으로 선언해주면 모든 형식타입을 허용한다.
String name;
Int age;
List<int> number = [0,1,2]
Map<String, int> score = {
‘en’: 100,
‘math’: 90,
}
String greet(){
print(‘hello’);
return ‘hello’;
}
연산자
~/
print(55~2) // 27
As
ㄴ>강제 형변환 키워드로
부모 타입 객체를 자식 타입 객체로 다운캐스팅 할떄 사용한다.
int n = 34;
double m = n as double;
Is/is! Age is int. / age is! Num
ㄴ> 타입을 확인해 true / false를 반환
Name?.length
ㄴ> 널인경우 에러를막고 값을 할당시킨다.
Name ?? 20
ㄴ> name이 null이면 20을 반환 값이 있으면 그 값을 반환.
스프레드 연산자
Var a = [1,2,3];
Var b = […a,4,5];
함수(메소드)
String see(String name){
return ‘Hi $name’;
}
또는
String see(String name) => ‘hi $name’;
Named parameter
{{}}파라미터를 중괄호로 감싸면 파라미터를 전달할수있다.
Void introduce({required String name, required int age}){
}
Optional parameter
[]대괄호로 감싸면 선택형 인자를 설정할수있다.
Void inroduces(String name, int age, [String? food]) {
}
Default parameter
Void inroduce(String name, int age, [String food = ‘whole’]){
}
Null Safety(flutter 2.0)
기본값 초기화 없이 선언하는 변수는 null값에 대한 안정성을 보장하기 위해서
타입을 nullable과 non-nullable로 구분해줘야한다.
*Nullable
일반 타입 뒤에 물음표를 붙여주면 해당 변수는 타입 또는 null이 될수있음을 나타낸다. 초기화없이 사용하면 null값으로 할당된다.
void main() {
String? name;
int? age;
bool? student;
print(name) //null
}
*non-nullable
물음표없이 일반 타입으로 사용하면 자동적으로 nul이 될수없는 값으로 인식된다.
사용전에 반드시 초기값을 할당해줘야한다.
Required, late
Required
함수에서 네임드 파라미터나 옵셔널 파라미터를 설정할때 non-nullable로
지정하기위해 타입 앞에 붙여준다.
Void greet({required String name}){
print(‘hello’);
}
Late
클래스에 non-nullable 프로퍼티가 필요하지만 디폴트값이나 초기화를 시키지 않을 경우 나중에 값을 할당한다는 의미로 붙여준다.
Class Cat{
late String name;
late int age;
}
중요한 메소드
Var list = [1,2,3,4];
Var newList = list;
print(newList);
Var spreadList = [10, …list, 100];
print(spreadList);
-map
map은 iterable(배열그룹)을 대상으로 foreach돌린다.
Var list = [1,2,3];
Var newList = list.map((e) => e+1);
list[0] = 0;
-asMap
배열 값에 index키 값을 삽입해줘서 반환해준다.
키값은 인덱스로 부여된다. 0부터 시작한다.
Var map = words.asMap();
-toList
생성되는 값들을 리스트로 만들어 반환한다.
List zero = orderList.toList();
Map.keys.toList() => [0,1,2,3];
-where
배열요소를 필터링한다.
Var list = [1,2,3,4];
Var filter = list.where((e) => e!=3);
//3이 아닌값만 필터링한다.
Print(filter); => [1,2,4];
-for / foreach
for(var e in list){
print(e);
}
List.forEach((e) => print(e));
-add / addAll / length / clear
Var vege = List();
생성자 사용
Var fruits = [‘apple’, ‘orange’];
문자열 사용하여 list생성
Fruits.add(‘kiwi’);
Fruits.addAll([‘grape’, ‘banana’]);
다수항목 추가하기
Var appleIndex = fruits.indexOf(‘apple’);
Fruits.removeAt(appleIndex);
리스트 단일 항목 삭제
Fruits.clear();
모든 항목 삭제
-sort
Fruits.sort((alb) => a.compareTo(b));
[‘b’, ‘banana’,a] => [a, b, banana’]이런식으로 순서대로 정렬된다.
-reduce
Int sum = number.reduce((total, element) => total + element);
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text(‘앱이다.’)),
body: Container(),
bottomNavigationBar: BottomAppBar(
child: Text('asdfdee')),
)
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ ],
body: SizedBox(
child: Icon(Icons.star,)
//아이콘은 컬러와 사이즈가 끝이다.
child: Text('안녕하세요',
style: TextStyle(color: Color(0xffd52727),
fontSize: 30, fontWeight: FontWeight.w700
),
),
),
Button(CSS)
: TextButton(child: Text(), onPressed: (){},)
안에는 2가지 옵션은 꼭 들어가야된다.
/ IconButton() / ElevatedButton()
이렇게 3가지를 쓸수있다.
1)TextButton
child: TextButton(
child: Text('글자'),
onPressed: (){},)
2)ElevatedButton
child: ElevatedButton(
child: Text('글자'),
onPressed: (){},
style: ButtonStyle(),
)
3)IconButton
child: IconButton(
icon: Icon(Icons.star),
onPressed: (){},)
appBar(Header)(CSS)
: 옵션
Title: 왼쪽제목
Leading: 왼쪽에 넣을 아이콘,(드롭바 같은경우)
Actions: [우측아이콘들]
AppBar(
leading: Icon(Icons.star),
Title: text(‘앱이다.’),
actions: [Icon(Icons.star), Icon(Icons.star)]
),
커스텀 위젯 문법
커스텀위젯은 class로 만든다.
: 밑에다가 그냥 쓰이는 부분을 컴포넌트화 시켜서
함수처럼 사용해준다.
재사용 많은 UI나 / 큰 페이지들 위주로 쓴다.
@override
함수를 쓰면서 중복되었을때
내꺼 먼저 써달라는 기호이다.
1)
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: ShopItem()
)
);
}
}
class ShopItem extends StatelessWidget {
const ShopItem({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
child: Text('안녕'),
);
}
}
2)변수로 선언해줘도 a 라고 써주면 사용 가능하다.
But 실시간으로 바뀌는 데이터들은 저렇게 변수 선언해서
사용하면 버그가 많이 생긴다.
var a = SizedBox(
child: Text('안녕'),
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: a
)
);
}
}