# 강의 제목 : 누적다운로드 120만+ 1인 개발자와 함께하는 앱 개발 입문 Online
# 강의 목표 : 기초부터 운영까지 앱 개발의 전체 프로세스를 이해한다.
내 이름으로 된 앱을 최대 10개까지 만들어 출시할 수 있다.
앱 개발자로 성장할 수 있는 초석을 다진다.
반응 얻는 앱의 특징과 노하우를 알아간다.
향후 강의 없이도 나만의 앱을 개발할수 있는 실력을 가진다.
# 강의 요약 : 프로그램 설치부터 기본 문법, 광고 다는 법, 클론코딩을 진행하며 필수 지식을 학습한다.
총 10개의 다른 주제로 실제 사용화 가능한 수준의 앱을 만들어본다.
나의 앱을 세상에 선보이기 위한 개발자 등록 및 배포를 진행한다.
강사님의 리뷰/클레임 대응사례 등 앱 성공 포인트를 참고해 1인 개발자로서의 입지를 다진다.
# 강의 목차 : Flutter 실전 앱 제작
- 앱 기능 및 디자인 설계 및 초기 구조 만들기
- TODO 화면 만들기
- TODO 화면 만들기 (9일차)
- TODO 화면 만들기
- TODO 기록 화면 만들기 (내부 DB 저장, 수정, 삭제)
- TODO 기록 화면 만들기 (이전 할일 기록 리스트, 카테고리 별 리스트)
- 앱 기능 및 디자인 설계 및 초기 구조 만들기 (일기앱)
- 일기 작성 화면 만들기
- 일기 작성 화면 만들기 (이모티콘 추가)
- 달력 화면 만들기
- 통계, 더보기 화면 만들기
- Splash 스크린 추가하기
# 강의 화면 :
# 강의 내용 : Flutter 실전 앱 제작 (TODO 화면 만들기)
# todo.dart
import 'package:flutter/material.dart';
import 'data/todo.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Todo> todos = [
Todo(
title: "온라인교육듣기1",
memo: "앱개발 강의 듣기",
color: Colors.redAccent.value,
done: 0,
category: "공부",
date: 20210709
),
Todo(
title: "온라인교육듣기2",
memo: "앱개발 강의 듣기",
color: Colors.blue.value,
done: 1,
category: "공부",
date: 20210709
),
];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(child: AppBar(),
preferredSize: Size.fromHeight(0),
),
body: ListView.builder(
itemBuilder: (ctx, idx){
if(idx == 0){
return Container(
child: Text("오늘하루", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
margin: EdgeInsets.symmetric(vertical: 12, horizontal: 20),
);
}else if(idx == 1){
List<Todo> undone = todos.where((t){
return t.done == 0;
}).toList();
return Container(
child: Column(
children: List.generate(undone.length, (_idx){
Todo t = undone[_idx];
return Container(
decoration: BoxDecoration(
color: Color(t.color),
borderRadius: BorderRadius.circular(16)
),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(t.title, style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold),),
Text(t.done == 0 ? "미완료" : "완료", style: TextStyle(color: Colors.white),)
],
),
Container(height: 8),
Text(t.memo)
]
)
);
}),
),
);
}
else if(idx == 2){
return Container(
child: Text("완료된 하루", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
margin: EdgeInsets.symmetric(vertical: 12, horizontal: 20),
);
}else if(idx == 3){
List<Todo> done = todos.where((t){
return t.done == 1;
}).toList();
return Container(
child: Column(
children: List.generate(done.length, (_idx){
Todo t = done[_idx];
return Container(
decoration: BoxDecoration(
color: Color(t.color),
borderRadius: BorderRadius.circular(16)
),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(t.title, style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold),),
Text(t.done == 0 ? "미완료" : "완료", style: TextStyle(color: Colors.white),)
],
),
Container(height: 8),
Text(t.memo)
]
)
);
}),
),
);
}
return Container();
},
itemCount: 4,
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.today_outlined),
label: "오늘"
),
BottomNavigationBarItem(
icon: Icon(Icons.assignment_ind_outlined),
label: "기록"
),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz),
label: "더보기"
),
],
),
);
}
}
# 실행 결과
# + 버튼 추가하기 main.dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(child: AppBar(),
preferredSize: Size.fromHeight(0),
),
// + 버튼 추가 하기
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add, color: Colors.white,),
onPressed: (){
// 화면 이동
},
),
# 실행 결과
# 화면 추가 하기
# write.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'data/todo.dart';
class TodoWritePage extends StatefulWidget {
final Todo todo;
TodoWritePage({Key key, this.todo}): super(key: key);
@override
State<StatefulWidget> createState(){
return _TodoWritePageState();
}
}
class _TodoWritePageState extends State<TodoWritePage> {
@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
actions: [
TextButton(
child: Text("저장", style: TextStyle(color:Colors.white),),
onPressed: (){
},
)
],
),
);
}
}
# main.dart
import 'package:flutter/material.dart';
import 'data/todo.dart';
import 'data/util.dart';
import 'write.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Todo> todos = [
Todo(
title: "온라인교육듣기1",
memo: "앱개발 강의 듣기",
color: Colors.redAccent.value,
done: 0,
category: "공부",
date: 20210709
),
Todo(
title: "온라인교육듣기2",
memo: "앱개발 강의 듣기",
color: Colors.blue.value,
done: 1,
category: "공부",
date: 20210709
),
];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(child: AppBar(),
preferredSize: Size.fromHeight(0),
),
// + 버튼 추가 하기
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add, color: Colors.white,),
onPressed: (){
// 화면 이동
Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => TodoWritePage(todo: Todo(
title: "",
color: 0,
memo: "",
done: 0,
category: "",
date: Utils.getFormatTime(DateTime.now())
))));
},
),
body: ListView.builder(
itemBuilder: (ctx, idx){
if(idx == 0){
return Container(
child: Text("오늘하루", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
margin: EdgeInsets.symmetric(vertical: 12, horizontal: 20),
);
}else if(idx == 1){
List<Todo> undone = todos.where((t){
return t.done == 0;
}).toList();
return Container(
child: Column(
children: List.generate(undone.length, (_idx){
Todo t = undone[_idx];
return Container(
decoration: BoxDecoration(
color: Color(t.color),
borderRadius: BorderRadius.circular(16)
),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(t.title, style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold),),
Text(t.done == 0 ? "미완료" : "완료", style: TextStyle(color: Colors.white),)
],
),
Container(height: 8),
Text(t.memo)
]
)
);
}),
),
);
}
else if(idx == 2){
return Container(
child: Text("완료된 하루", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
margin: EdgeInsets.symmetric(vertical: 12, horizontal: 20),
);
}else if(idx == 3){
List<Todo> done = todos.where((t){
return t.done == 1;
}).toList();
return Container(
child: Column(
children: List.generate(done.length, (_idx){
Todo t = done[_idx];
return Container(
decoration: BoxDecoration(
color: Color(t.color),
borderRadius: BorderRadius.circular(16)
),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(t.title, style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold),),
Text(t.done == 0 ? "미완료" : "완료", style: TextStyle(color: Colors.white),)
],
),
Container(height: 8),
Text(t.memo)
]
)
);
}),
),
);
}
return Container();
},
itemCount: 4,
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.today_outlined),
label: "오늘"
),
BottomNavigationBarItem(
icon: Icon(Icons.assignment_ind_outlined),
label: "기록"
),
BottomNavigationBarItem(
icon: Icon(Icons.more_horiz),
label: "더보기"
),
],
),
);
}
}
# 실행 결과
# 교육 소감
오늘은 main.dart 에서 완료된 하루와 미완료된 하루의 화면을 디자인 하고, + 버튼을 추가하여 todo의 할일을 기록하는 페이지를 만들었다. + 버튼은 floating action button 을 추가하여 onpress() 함수를 통하여 클릭시 todo를 기록할수 있을 widget을 호출하게 하였다. done이라는 field 값을 주고 0일 경우 오늘 하루 미완료되게 표시하고 done 이라는 field값을 1일때, 완료된 하루로 표시할수 있게 하였다. 또한 todo list 를 작성할수 있는 페이지를 만들기 위해 폴더에 write.dart를 만들고, Stateful widget을 만들었다. 글을 작성하면 글이 변경되어야하고, 색상을 변경하면 색상도 변경되어야 하므로 Stateful widget을 써야한다. import 기능을 사용하여 다른 폴더에 있는 dart 파일을 사용할경우 경로를 설정 해야 하며, 해당 dart 에서 import 된 dart 를 사용할 수 있다. 또한 widget의 실제 state를 가지고 있는 class 를 만들어야 하며,widget build 를 만들어 appbar()를 넣고 실제 저장하기 위한 text button 도 만들었다. 또한 main.dart 에서 화면을 이동하기 위해서 navigator push 를 통해서 화면을 이동할수 있게 구현 하였다.
# 본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.
'코딩 알로하 :: two > 하이브리드앱' 카테고리의 다른 글
패스트캠퍼스 챌린지 11일차 (0) | 2021.11.11 |
---|---|
패스트캠퍼스 챌린지 10일차 (0) | 2021.11.11 |
패스트캠퍼스 챌린지 8일차 (0) | 2021.11.08 |
패스트캠퍼스 챌린지 7일차 (0) | 2021.11.07 |
패스트캠퍼스 챌린지 6일차 (0) | 2021.11.06 |
댓글