๐ Today I Learned 12ํ์ฐจ - Flutter ๋์งํธ ์ฃผ์ฌ์ ์ฑ ๋ง๋ค๊ธฐ ๐ฒ
๐ Flutter ๋์งํธ ์ฃผ์ฌ์ ์ฑ ๋ง๋ค๊ธฐ
๐ฏ ํ์ต ๋ชฉํ
- ๋์งํธ ์ฃผ์ฌ์ ์ฑ ๋ง๋ค๊ธฐ
- TabController์ TickerProviderStateMixin ํ์ฉ๋ฒ ์ตํ๊ธฐ
- ๊ฐ์๋๊ณ์ ์์ด๋ก์ค์ฝํ ์๋ฆฌ ์ดํดํ๊ธฐ
- ํ๋ค๋ฆผ ๊ฐ์ง ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
๐ ์ฃผ์ ๋ด์ฉ
โญ ํ๋ก์ ํธ ๊ตฌ์ฑ ์๊ตฌ์ฌํญ
- ๊ฐ์๋๊ณ๋ ๊ฐ์๋๋ฅผ ์ธก์ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ ์ ๋์ ๊ฐ์ ์์น๋ฅผ ํ๋๋ ํ๋์ผ๋ก ์ธ์ํ ์ง์ ๋ํ ๊ธฐ์ค์ด ์ค์
- ์ฌ์ฉ์๊ฐ ํน์ ์์น๋ฅผ ๋๋ ๊ฐ๋๋ก ํธ๋ํฐ์ ํ๋ ์๊ฐ์ ์ธ์ํ ์ ์๋ ํจ์๋ฅผ ๊ตฌํ
- ๊ทธ ๊ธฐ์ค์ Slider ์์ ฏ์ ํตํด ์ค์
- ํ๋ฉด 2๊ฐ๋ฅผ ๋ง๋ค์ด ํญ๊ณผ ์คํฌ๋กค๋ก ์ด๋(๋ ํ๋ฉด์ ๊ฐ๊ฐ ๋ฐ๋ก ์์ ฏ์ผ๋ก ๊ตฌํํ๊ณ BottomNavigationBar๋ฅผ ์ด์ฉ)
๐ช ์ฌ์ ์ง์
๊ฐ์๋๊ณ
๊ฐ์๋๊ณ๋ฅผ ์ฌ์ฉํ๋ฉด x,y,z ์ถ์ ์ธก์ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ double ๊ฐ์ผ๋ก ๋ฐํ
์์ด๋ก์ค์ฝํ
๊ฐ์๋๊ณ๋ x,y,z ์ถ์ ์ง์ ์์ง์๋ง ์ธก์ ํ ์ ์๋ค. ์์ด๋ก์ค์ฝํ๋ ์ด ๋จ์ ์ ๋ณด์ํด์ x,u,z ์ถ์ ํ์ ์ ์ธก์ ํ ์ ์์ต๋๋ค.
x: ์ข์ฐ๋ก ํ์ ํ๋ ๋ฐฉํฅ y: ์์๋๋ก ํ์ ํ๋ ๋ฐฉํฅ z: ์๋ค๋ก ํ์ ํ๋ ๋ฐฉํฅ
โก ํต์ฌ ๊ตฌํ ์ง์
- TabController์์ vsync ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๋ฉด ํ์๋ก TickerProviderStateMixin์ ์ฌ์ฉํด์ผํฉ๋๋ค.
- TickerProviderStateMixin๊ณผ SingleTickerProviderMixin์ ์ ๋๋ฉ์ด์ ์ ํจ์จ์ ์ฌ๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
- vsync๋ TickerProviderStateMixin์ ์ฌ์ฉํ๋ state ํด๋์ค๋ฅผ this ํํ๋ก ๋ฃ์ด์ฃผ๋ฉด ๋ฉ๋๋ค.
- ๊ทธ๋ฌ๋ฉด controller๋ฅผ ์ด์ฉํด์ TabBarView๋ฅผ ์กฐ์ํ ์ ์์ต๋๋ค.
TickerProviderStateMixin ์ฌํ ์ดํด
๐ก ํต์ฌ: TickerProviderStateMixin์ โ์ ๋๋ฉ์ด์ ์ ์ํ ์ฌ์ฅ ๋ฐ๋๊ธฐโ๋ผ๊ณ ์๊ฐํ๋ฉด ์ดํดํ๊ธฐ ์ฝ์ต๋๋ค.
๐ฑ Ticker: ์ ๋๋ฉ์ด์ ์ ์ฌ์ฅ ๋ฐ๋
์ ๋๋ฉ์ด์ ์ ๋ณธ์ง์ ์ผ๋ก ์์ฃผ ์งง์ ์๊ฐ ๋์ ํ๋ฉด์ ๊ณ์ํด์ ๋ค์ ๊ทธ๋ฆฌ๋ ์์ ์ ๋๋ค. ์๋ฅผ ๋ค์ด, 1์ด ๋์ ์ด๋ค ์์ ฏ์ด ์ ์ ์ปค์ง๋ ์ ๋๋ฉ์ด์ ์ ์ฌ์ค 1์ด ๋์ ์ฝ 60๋ฒ(60fps ๊ธฐ์ค)์ ๊ฑธ์ณ ์์ ฏ์ ํฌ๊ธฐ๋ฅผ ๋ฏธ์ธํ๊ฒ ํค์ฐ๋ฉด์ ํ๋ฉด์ ์๋ก๊ณ ์นจํ๋ ๊ฒ์ ๋๋ค.
์ด๋, โ์ง๊ธ ๋ค์ ๊ทธ๋ ค!โ, โ๋ ๋ค์ ๊ทธ๋ ค!โ์ ๊ฐ์ด ์ผ์ ํ ๊ฐ๊ฒฉ์ผ๋ก ์ ํธ๋ฅผ ๋ณด๋ด์ฃผ๋ ์ญํ ์ ํ๋ ๊ฒ์ด ๋ฐ๋ก Ticker
์
๋๋ค.
๐ TickerProviderStateMixin ์ด๋ฆ ๋ถ์
๊ตฌ์ฑ ์์ | ์ญํ | ์ค๋ช |
---|---|---|
Ticker | ์ฌ์ฅ ๋ฐ๋ | ์ ๋๋ฉ์ด์ ํ๋ ์๋ง๋ค ์ ํธ๋ฅผ ์ฃผ๋ ์ฌ์ฅ ๋ฐ๋ |
Provider | ์ ๊ณต์ | Ticker๋ฅผ AnimationController์๊ฒ ์ ๊ณตํ๋ ์ญํ |
State | ์ํ ๊ด๋ฆฌ | StatefulWidget์ ์๋ช ์ฃผ๊ธฐ์ ์ ๋๋ฉ์ด์ ๋๊ธฐํ |
Mixin | ๊ธฐ๋ฅ ์ถ๊ฐ | with ํค์๋๋ก State ํด๋์ค์ ๊ธฐ๋ฅ ์ฅ์ฐฉ |
โก ํจ์จ์ฑ์ ํต์ฌ: vsync
- ๋ฌธ์ ์ํฉ: Ticker๊ฐ ํ๋ฉด ์ํ์ ์๊ด์์ด ๊ณ์ ์ ํธ๋ฅผ ๋ณด๋ด๋ฉด CPU์ ๋ฐฐํฐ๋ฆฌ ๋ญ๋น ๐
- ํด๊ฒฐ์ฑ
:
vsync
(Vertical Synchronization)๋ฅผ ํตํด ํ๋ฉด ์ฃผ์ฌ์จ์ ๋ง์ถฐ ๋๊ธฐํ -
ํจ๊ณผ: ํ๋ฉด์ด ๋ณด์ผ ๋๋ง ์๋ํ๊ณ , ๋ฐฑ๊ทธ๋ผ์ด๋ ์ ํ ์ ์๋์ผ๋ก ๋ฉ์ถค
- initState์์ TabController์ Listener๋ฅผ ๋ฑ๋กํด์ controller์ ์์ฑ์ด ๋ณ๊ฒฝ๋ ๋ ๋ง๋ค setState๋ฅผ ์คํํด์ ํ๋ฉด์ ๋ค์ ๊ทธ๋ฆด ์ ์๋๋ก ํฉ๋๋ค.
๐ป ์ค์ต ๋ฐ ์์
๐ง ์ค์ ์์ฑ ์ฝ๋
import 'package:flutter/material.dart';
import 'package:random_dice/const/colors.dart';
import 'package:random_dice/screen/home_screen.dart';
import 'package:random_dice/screen/root_screen.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(
scaffoldBackgroundColor: backgroundColor,
sliderTheme: SliderThemeData(
thumbColor: primaryColor,
activeTickMarkColor: primaryColor,
inactiveTickMarkColor: primaryColor.withOpacity(0.3),
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
selectedItemColor: primaryColor,
unselectedItemColor: secondaryColor,
backgroundColor: backgroundColor,
),
),
home: RootScreen(),
),
);
}
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:random_dice/screen/home_screen.dart';
import 'package:random_dice/screen/settings_screen.dart';
import 'package:shake/shake.dart';
class RootScreen extends StatefulWidget {
const RootScreen({super.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 = Random();
setState(() {
number = rand.nextInt(5) + 1;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: TabBarView(controller: controller, children: renderChildren()),
bottomNavigationBar: renderBottomNavigation(),
);
}
@override
void dispose() {
controller!.removeListener(tabListener);
shakeDetector!.stopListening();
super.dispose();
}
void tabListener() {
setState(() {});
}
void onThresholdChange(double value) {
setState(() {
threshold = value;
});
}
List<Widget> renderChildren() {
return [
HomeScreen(number: number),
SettingsScreen(
threshold: threshold,
onThresholdChange: onThresholdChange,
),
];
}
BottomNavigationBar renderBottomNavigation() {
return BottomNavigationBar(
currentIndex: controller!.index,
onTap: (index) {
setState(() {
controller!.animateTo(index);
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.edgesensor_high_outlined),
label: '์ฃผ์ฌ์',
),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: '์ค์ '),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:random_dice/const/colors.dart';
class HomeScreen extends StatelessWidget {
final int number;
const HomeScreen({super.key, required this.number});
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(child: Image.asset('asset/img/$number.png')),
SizedBox(height: 32),
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,
),
),
],
);
}
}
๐ฑ ๊ตฌํ ๊ฒฐ๊ณผ
.png)
๋ฉ์ธ ์ฃผ์ฌ์ ํ๋ฉด
.png)
ํ๋ค๋ฆผ ๊ฐ๋ ์ค์ ํ๋ฉด
๐ ๋ง๋ฌด๋ฆฌ
โ ์ค๋ ๋ฐฐ์ด ๊ฒ
- TabController์ TickerProviderStateMixin: ํญ ๋ค๋น๊ฒ์ด์ ๊ณผ ์ ๋๋ฉ์ด์ ํจ์จ์ฑ ๊ด๋ฆฌ
- ๊ฐ์๋๊ณ์ ์์ด๋ก์ค์ฝํ: ์ผ์ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ ํ๋ค๋ฆผ ๊ฐ์ง ์๋ฆฌ
- ShakeDetector: ํ๋ค๋ฆผ ๊ฐ์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ๋ฒ
- Bottom Navigation: ํญ ๋ฐ๋ฅผ ํตํ ํ๋ฉด ์ ํ ๊ตฌํ
- Slider Widget: ์ฌ์ฉ์ ์ค์ ๊ฐ ์กฐ์ UI ๊ตฌํ
- ์ํ ๊ด๋ฆฌ: ์ฌ๋ฌ ํ๋ฉด ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๋ฐ ์ํ ๋๊ธฐํ
๐ ๋ค์ ๊ณํ
- ๊ณ ๊ธ ์ผ์ ํ์ฉ: ๋ ์ ๊ตํ ์ ์ค์ฒ ์ธ์ ๊ธฐ๋ฅ ์ถ๊ฐ
- ์ ๋๋ฉ์ด์ ๊ฐํ: ์ฃผ์ฌ์ ๊ตด๋ฆฌ๊ธฐ ์ ๋๋ฉ์ด์ ํจ๊ณผ ๊ตฌํ
- ์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์ : ํ ํฑ ํผ๋๋ฐฑ๊ณผ ์ฌ์ด๋ ํจ๊ณผ ์ถ๊ฐ
- ๋ฐ์ดํฐ ์ ์ฅ: SharedPreferences๋ฅผ ํ์ฉํ ์ค์ ๊ฐ ์๊ตฌ ์ ์ฅ
๐ก ํต์ฌ: Flutter์์ ์ผ์์ ํญ ๋ค๋น๊ฒ์ด์ ์ ๊ฒฐํฉํ์ฌ ์ค์ฉ์ ์ธ ์ฑ์ ๋ง๋ค ์ ์์์ต๋๋ค. TickerProviderStateMixin์ ์ค์์ฑ๊ณผ ํจ์จ์ ์ธ ์ ๋๋ฉ์ด์ ๊ด๋ฆฌ๋ฒ์ ์ฒด๋ํ์ต๋๋ค! ๐ฒ
๋๊ธ๋จ๊ธฐ๊ธฐ