# 강의 제목 : 누적다운로드 120만+ 1인 개발자와 함께하는 앱 개발 입문 Online
# 강의 목표 : 기초부터 운영까지 앱 개발의 전체 프로세스를 이해한다.
내 이름으로 된 앱을 최대 10개까지 만들어 출시할 수 있다.
앱 개발자로 성장할 수 있는 초석을 다진다.
반응 얻는 앱의 특징과 노하우를 알아간다.
향후 강의 없이도 나만의 앱을 개발할수 있는 실력을 가진다.
# 강의 요약 : 프로그램 설치부터 기본 문법, 광고 다는 법, 클론코딩을 진행하며 필수 지식을 학습한다.
총 10개의 다른 주제로 실제 사용화 가능한 수준의 앱을 만들어본다.
나의 앱을 세상에 선보이기 위한 개발자 등록 및 배포를 진행한다.
강사님의 리뷰/클레임 대응사례 등 앱 성공 포인트를 참고해 1인 개발자로서의 입지를 다진다.
# 강의 목차 : Flutter 실전 앱 제작
- 앱 기능 및 디자인 설계 및 초기 구조 만들기 (눈바디앱)
- 식단 기록 페이지
- 눈바디 운동 기록 페이지
- 달력 기록 페이지
- 달력 기록 페이지 2
- 통계 갤러리 알림 설정하기 - 29일차
- 다크모드 지원하기 - 29일차
# 강의 화면 :
# 강의 내용 : 통계 갤러리 알림 설정하기 및 다크모드 지원하기
1. 통계 페이지 만들기
- 이전 기록을 모두 확인 하기
# main.dart
void getAllHistories() async {
todayFood = await dbHelper.queryAllFood();
todayWorkout = await dbHelper.queryAllWorkout();
todayEyeBody = await dbHelper.queryAllEyeBody();
setState(() {
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: getPage(),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: "오늘"
),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
label: "기록"
),
BottomNavigationBarItem(
icon: Icon(Icons.bar_chart),
label: "통계"
),
BottomNavigationBarItem(
icon: Icon(Icons.photo_album_outlined),
label: "갤러리"
),
],
currentIndex: currentIndex,
onTap: (idx){
setState(() {
currentIndex = idx;
if(currentIndex == 0 || currentIndex == 1){
time = DateTime.now();
getHistories();
}else if(currentIndex == 2 || currentIndex == 3){
getAllHistories();
}
});
},
),
floatingActionButton: [2, 3].contains(currentIndex) ? Container() : FloatingActionButton(
onPressed: (){
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
builder: (ctx){
return SizedBox(
height: 200,
child: Column(
children: [
TextButton(child: Text("식단"),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => FoodAddPage(
food: Food(
date: Utils.getFormatTime(time),
kcal: 0,
memo: "",
type: 0,
image: ""
),
))
);
getHistories();
},),
TextButton(child: Text("운동"),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => WorkoutAddPage(
workout: Workout(
date: Utils.getFormatTime(time),
time: 0,
memo: "",
name: "",
image: ""
),
))
);
getHistories();
},),
TextButton(child: Text("눈바디"),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) => EyeBodyAddPage(
eyeBody: EyeBody(
date: Utils.getFormatTime(time),
weight: 0,
image: ""
),
))
);
getHistories();
},),
],
),
);
}
);
},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
2. 총기록 식단수, 운동수, 눈바디수 표시하기
# main.dart
Widget getChartPage(){
return Container(
child: Column(children: [
getMainPage(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text("총 기록 식단 수\n${todayFood.length}"),
Text("총 기록 운동 수\n${todayWorkout.length}"),
Text("총 기록 눈바디 수\n${todayEyeBody.length}"),
],
)
]),
);
}
3. 갤러리 페이지에서 상세 확인하기
Widget getGalleryPage(){
return Container(
child: GridView.count(
crossAxisCount: 3,
childAspectRatio: 1,
children: List.generate(
todayEyeBody.length, (idx){
return EyeBodyCard(eyeBody: todayEyeBody[idx]);
}
),
),
);
}
4. 알림 구현하기
pubspec.yaml -> flutter_local_notifications: ^4.0.1+2 추가하기
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0
sqflite: ^1.3.2+4
multi_image_picker: ^4.7.12
table_calendar: ^2.3.3
flutter_local_notifications: ^4.0.1+2
# main.dart
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runZonedGuarded(() async {
runApp(MyApp());
}, (error, stackTrace){
FirebaseCrashlytics.instance.recordError(error, stackTrace);
});
tz.initializeTimeZones();
const AndroidNotificationChannel androidNotificationChannel = AndroidNotificationChannel("fastcampus", "eyebody", "eyebody notification");
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(
androidNotificationChannel);
}
5. notification 초기화
Future<bool> initNotification() async {
if(flutterLocalNotificationsPlugin == null){
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
}
var initSettingAndroid = AndroidInitializationSettings("app_icon");
var initiOS = IOSInitializationSettings();
var initSetting = InitializationSettings(
android: initSettingAndroid, iOS: initiOS
);
await flutterLocalNotificationsPlugin.initialize(initSetting,
onSelectNotification: (payload) async {
}
);
setScheduling();
return true;
}
6. 스케줄링 구현하기
void setScheduling() async{
var android = AndroidNotificationDetails(
"fastcampus", "eyebody", "eyebody notification",
importance: Importance.max,
priority: Priority.max);
var ios = IOSNotificationDetails();
NotificationDetails detail = NotificationDetails(
iOS: ios,
android: android
);
flutterLocalNotificationsPlugin.zonedSchedule(
0, "오늘 다이어트를 기록해주세요!",
"앱에서 기록을 알려주세요!!",
tz.TZDateTime.from(DateTime.now().add(Duration(seconds: 10)), tz.local),
detail,
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
payload: "eyebody",
matchDateTimeComponents: DateTimeComponents.time
);
}
7. UI 다크모드 하기
- Scaffold의 background color 를 Colors.black87 등
- IOS 다크모드 칼러 확인
https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode
class WorkoutCard extends StatelessWidget {
final Workout workout;
WorkoutCard({Key key, this.workout}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(8),
child: ClipRRect(
child: Stack(
children: [
Positioned.fill(
child: AssetThumb(asset: Asset(workout.image, "food.png", 0, 0), width: 300, height: 300),
),
Positioned.fill(
child: Container(color: Colors.black38),
),
Container(
alignment: Alignment.center,
child: Text("${workout.name}", style: TextStyle(color: Colors.white),),
)
],
),
borderRadius: BorderRadius.circular(8),
),
);
}
}
# 교육 소감
# 본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.
'코딩 알로하 :: two > 하이브리드앱' 카테고리의 다른 글
패스트캠퍼스 챌린지 31일차 (0) | 2021.12.01 |
---|---|
패스트캠퍼스 챌린지 30일차 (0) | 2021.11.30 |
패스트캠퍼스 챌린지 28일차 (0) | 2021.11.28 |
패스트캠퍼스 챌린지 27일차 (0) | 2021.11.27 |
패스트캠퍼스 챌린지 26일차 (0) | 2021.11.26 |
댓글