Must Have 코드팩토리의 플러터 프로그래밍 - 10 ~ 11
book
Must Have 코드팩토리의 플러터 프로그래밍 10 ~ 11
10장 [Project] 만난 지 며칠 U&I
P.250 (.of 생성자)
.of 생성자 : BuildContext를 매개변수로 받고 위젯 트리에서 가장 가까이에 있는 객체의 값을 찾음.
P.269 (10.5)
테스트하기 : 최종 완성본 결과
// lib/main.dart
import 'package:blog_web_app/screen/home_screen.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: HomeScreen(),
),
);
}
// lib/screen/home_screen.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
DateTime firstDay = DateTime.now();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink[100],
body: SafeArea(
top: true,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_DDay(
firstDay: firstDay,
onHeartPressed: onHeartPressed,
),
_CoupleImage(),
],
),
),
);
}
void onHeartPressed() {
showCupertinoDialog(
context: context,
builder: (context) {
return Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.white,
height: 300,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
onDateTimeChanged: (DateTime date) {
setState(() {
firstDay = date;
});
},
),
),
);
},
barrierDismissible: true,
);
}
}
class _DDay extends StatelessWidget {
final DateTime firstDay;
final GestureTapCallback onHeartPressed;
const _DDay(
{super.key, required this.firstDay, required this.onHeartPressed});
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final now = DateTime.now();
return Column(
children: [
SizedBox(height: 16),
Text(
'U&I',
style: textTheme.headline1,
),
SizedBox(height: 16),
Text(
'우리 처음 만난 날',
style: textTheme.bodyText1,
),
Text(
'${firstDay.year}.${firstDay.month}.${firstDay.day}',
style: textTheme.bodyText2,
),
SizedBox(height: 16),
IconButton(
iconSize: 60.0,
icon: Icon(
Icons.favorite,
color: Colors.red,
),
onPressed: onHeartPressed,
),
SizedBox(height: 16),
Text(
'D+${DateTime(now.year, now.month, now.day).difference(firstDay).inDays + 1}',
style: textTheme.headline2,
),
],
);
}
}
class _CoupleImage extends StatelessWidget {
const _CoupleImage({super.key});
@override
Widget build(BuildContext context) {
return Expanded(
child: Center(
child: Image.asset(
'asset/image/middle_image.png',
height: MediaQuery.of(context).size.height / 2,
),
),
);
}
}
11장 [Project] 디지털 주사위
P.275 (11.1.3)
Sensor_Plus 패키지 : 핸드폰의 가속도계와 자이로스코프 센서를 사용.
P.297 (11.5)
테스트하기 : 최종 완성본 결과
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:random_dice/const/colors.dart';
import 'package:random_dice/screen/root_screen.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: backgroundColor,
sliderTheme: SliderThemeData(
thumbColor: primaryColor,
activeTrackColor: primaryColor,
inactiveTrackColor: primaryColor.withOpacity(0.3),
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
selectedItemColor: primaryColor,
unselectedItemColor: secondaryColor,
backgroundColor: backgroundColor,
),
),
home: RootScreen(),
),
);
}
// lib/screen/home_screen.dart
import 'package:random_dice/const/colors.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
final int number;
const HomeScreen({
required this.number,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset('asset/image/$number.png'),
),
SizedBox(height: 32.0),
Text(
'행운의 숫자',
style: TextStyle(
color: secondaryColor,
fontSize: 20.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 12.0),
Text(
number.toString(),
style: TextStyle(
color: primaryColor,
fontSize: 60.0,
fontWeight: FontWeight.w200,
),
),
],
);
}
}
// lib/screen/root_screen.dart
import 'package:flutter/material.dart';
import 'package:random_dice/screen/home_screen.dart';
import 'package:random_dice/screen/settings_screen.dart';
import 'dart:math';
import 'package:shake/shake.dart';
class RootScreen extends StatefulWidget {
const RootScreen({Key? key}) : super(key: key);
@override
State<RootScreen> createState() => _RootScreenState();
}
class _RootScreenState extends State<RootScreen> with TickerProviderStateMixin {
TabController? controller;
double threshold = 2.7;
int number = 1;
ShakeDetector? shakeDetector;
@override
void initState() {
super.initState();
controller = TabController(length: 2, vsync: this);
controller!.addListener(tabListener);
shakeDetector = ShakeDetector.autoStart(
shakeSlopTimeMS: 100,
shakeThresholdGravity: threshold,
onPhoneShake: onPhoneShake,
);
}
void onPhoneShake() {
final rand = new Random();
setState(() {
number = rand.nextInt(5) + 1;
});
}
tabListener() {
setState(() {});
}
@override
dispose() {
controller!.removeListener(tabListener);
shakeDetector!.stopListening();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: TabBarView(
controller: controller,
children: renderChildren(),
),
bottomNavigationBar: renderBottomNavigation(),
);
}
List<Widget> renderChildren() {
return [
HomeScreen(number: number),
SettingsScreen(
threshold: threshold,
onThresholdChange: onThresholdChange,
),
];
}
void onThresholdChange(double val) {
setState(() {
threshold = val;
});
}
BottomNavigationBar renderBottomNavigation() {
return BottomNavigationBar(
currentIndex: controller!.index,
onTap: (int index) {
setState(() {
controller!.animateTo(index);
});
},
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.edgesensor_high_outlined,
),
label: '주사위',
),
BottomNavigationBarItem(
icon: Icon(
Icons.settings,
),
label: '설정',
),
],
);
}
}
// lib/screen/setting_screen.dart
import 'package:random_dice/const/colors.dart';
import 'package:flutter/material.dart';
class SettingsScreen extends StatelessWidget {
final double threshold;
final ValueChanged<double> onThresholdChange;
const SettingsScreen({
Key? key,
required this.threshold,
required this.onThresholdChange,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: Row(
children: [
Text(
'민감도',
style: TextStyle(
color: secondaryColor,
fontSize: 20.0,
fontWeight: FontWeight.w700,
),
),
],
),
),
Slider(
min: 0.1,
max: 10.0,
divisions: 101,
value: threshold,
onChanged: onThresholdChange,
label: threshold.toStringAsFixed(1),
),
],
);
}
}
참고
이 글은 골든래빗 《Must Have 코드팩토리의 플러터 프로그래밍 2판》의 스터디 내용 입니다.
스터디
Q.
A.