Skip to content

Instantly share code, notes, and snippets.

@temoki
Last active December 16, 2024 11:59
Show Gist options
  • Save temoki/aedf93fcc19ea97fc6b94622d53dc87a to your computer and use it in GitHub Desktop.
Save temoki/aedf93fcc19ea97fc6b94622d53dc87a to your computer and use it in GitHub Desktop.
//================================================================================
// Flutter State Management Guide (2)
//
// ๅ‰ๅ›žใฎ็ถšใ
// https://gist.github.com/temoki/0e9acedbfa2b6ebe424f7e856dc2f5f3
//================================================================================
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
final items = <Widget>[
Item((_) => PageA(), '[A] WidgetใŒใƒชใƒ“ใƒซใƒ‰ใ•ใ‚Œใ‚‹ใ‚ฟใ‚คใƒŸใƒณใ‚ฐ'),
Item((_) => PageB(), '[B] Widgetใฎใƒฉใ‚คใƒ•ใ‚ตใ‚คใ‚ฏใƒซ'),
Item((_) => PageC(), '[C] Flutter Hooks ใฎๅŸบๆœฌ (useState)'),
Item((_) => PageD(), '[D] Flutter Hooks ใฎๅŸบๆœฌ (useEffect)'),
Item((_) => PageE(), '[E] Flutter Hooks ใฎๅŸบๆœฌ (use~Controller)'),
Item((_) => PageF(), '[F] Riverpod ใฎๅ„ๆฉŸ่ƒฝ'),
];
//================================================================================
// [A] Widget ใŒใƒชใƒ“ใƒซใƒ‰ใ•ใ‚Œใ‚‹ใ‚ฟใ‚คใƒŸใƒณใ‚ฐใซใคใ„ใฆ
//================================================================================
final class PageA extends StatelessWidget {
const PageA({super.key});
@override
Widget build(BuildContext context) => CounterWidget();
}
// (1) Countๅ€คใ‚’็Šถๆ…‹ใซๆŒใคใ‚ˆใใ‚ใ‚‹ StatefulWidget ใ‚’ไพ‹ใซ่งฃ่ชฌใ—ใฆใ„ใใพใ™ใ€‚
final class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => CounterState();
}
final class CounterState extends State<CounterWidget> {
CounterState();
int _count = 0;
@override
void initState() {
debugPrint('[CounterState] initState');
super.initState();
}
@override
Widget build(BuildContext context) {
debugPrint('[CounterState] build');
return Center(
// (5) ใ“ใฎ Rainbow ใฏ่‡ช่บซใŒใƒชใƒ“ใƒซใƒˆใ•ใ‚Œใ‚‹ใจๆž ใฎ่‰ฒใŒๅค‰ใ‚ใ‚‹ใ‚ˆใ†ใซใชใฃใฆใ„ใพใ™ใ€‚
// ๏ผ‹ใƒœใ‚ฟใƒณใ‚’ๆŠผใ™ใŸใณใซ CounterWidget ใŒใƒชใƒ“ใƒซใƒ‰ใ•ใ‚Œใ€ใใฎ ๅญWidget ใซใ‚‚ไผๆฌใ—ใพใ™ใ€‚
// Rainbow ใงๅ›ฒใพใ‚ŒใŸ ๅ„Widget ใฎ่‰ฒใŒๅค‰ใ‚ใ‚‹ใ“ใจใง ๅญWidget ใฎใƒชใƒ“ใƒซใƒ‰ใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚
child: Rainbow(
child: Container(
width: 200,
padding: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// (6) ใŸใ ใ—ใ€ใ“ใฎ Rainbow ใฏๆž ใฎ่‰ฒใŒๅค‰ใ‚ใ‚Šใพใ›ใ‚“ใ€‚
// const๏ผˆ๏ผไธๅค‰ใชใ‚‚ใฎ๏ผ‰ใจใ—ใฆๅฎš็พฉใ•ใ‚Œใฆใ„ใ‚‹ใŸใ‚ใงใ™ใ€‚
// ไธ่ฆใชใƒชใƒ“ใƒซใƒ‰ใ‚’ๆŠ‘ใˆใ‚‹ใŸใ‚ใซๅฏ่ƒฝใชใ‚‚ใฎใฏ const ใซใ™ใ‚‹ใฎใŒ่‰ฏใ„ใงใ™ใ€‚
const Rainbow(
child: Text('Count', textAlign: TextAlign.center),
),
// (7) ใ“ใฎ Widget ใฏ Count ใจใ„ใ†ๅค‰ๆ•ฐใซไพๅญ˜ใ™ใ‚‹ใฎใง const ใซใงใใพใ›ใ‚“ใ€‚
Rainbow(
// (4) ใƒชใƒ“ใƒซใƒ‰ๆ™‚ใซๆ›ดๆ–ฐใ•ใ‚ŒใŸ Countๅ€ค ใ‚’ไฝฟใ†ใฎใง UI ไธŠใฎ Countๅ€ค ใ‚‚ๆ›ดๆ–ฐใ•ใ‚Œใพใ™ใ€‚
child: Text('$_count', textAlign: TextAlign.center),
),
const SizedBox(height: 24),
Rainbow(
// (2) ใ“ใฎ๏ผ‹ใƒœใ‚ฟใƒณใ‚’ๆŠผใ™ใจ Countๅ€ค ใŒใ‚คใƒณใ‚ฏใƒชใƒกใƒณใƒˆใ•ใ‚Œใพใ™ใ€‚
child: FilledButton(
// (3) ใƒœใ‚ฟใƒณๆŠผไธ‹ๆ™‚ใซ setState() ใง Countๅ€ค ใ‚’ๆ›ดๆ–ฐใ—ใฆใ„ใพใ™ใ€‚
// StatefulWidget ใฏ setState() ใ‚’ใƒˆใƒชใ‚ฌใƒผใซ่‡ช่บซใ‚’ใƒชใƒ“ใƒซใƒ‰ใ—ใพใ™ใ€‚
onPressed: () => setState(() => _count++),
child: const Text('+'),
),
),
],
),
),
),
);
}
}
// (8) const ใซใงใใ‚‹ Widget ใ‚’ๅฎš็พฉใ™ใ‚‹ใŸใ‚ใฎๆกไปถ
// ใ‚นใƒผใƒ‘ใƒผใ‚ฏใƒฉใ‚นใŒ const ใงใ‚ใ‚‹๏ผˆ้žconstใช NonConstClass ใซๅค‰ๆ›ดใ—ใŸใ‚‰...๏ผ‰
class SomeClass extends ConstClass {
// ใ‚ณใƒณใ‚นใƒˆใƒฉใ‚ฏใ‚ฟใŒ const ใงใ‚ใ‚‹
const SomeClass({required this.value1, required this.value2}) : super();
// ใ™ในใฆใฎใƒ•ใ‚ฃใƒผใƒซใƒ‰ใŒ final ใงใ‚ใ‚‹๏ผˆไธ€้ƒจใฎใƒ•ใ‚ฃใƒผใƒซใƒ‰ใฎ final ใ‚’ๅค–ใ™ใจ...๏ผ‰
final int value1;
final int value2;
}
class ConstClass {
const ConstClass();
}
class NonConstClass {
NonConstClass();
}
//================================================================================
// [B] Widgetใฎใƒฉใ‚คใƒ•ใ‚ตใ‚คใ‚ฏใƒซ
//================================================================================
// (1) ใใ‚‚ใใ‚‚ Widget ใฏใƒ“ใƒซใƒ‰ใฎใŸใณใซๆ–ฐใ—ใ„ใ‚คใƒณใ‚นใ‚ฟใƒณใ‚นใŒๅ†็”Ÿๆˆใ•ใ‚Œใพใ™๏ผˆconstใ‚’้™คใ๏ผ‰ใ€‚
// ใƒชใƒ“ใƒซใƒ‰ใง StatefulWidget ใŒๅ†็”Ÿๆˆใ•ใ‚Œใฆใ‚‚ใ€ใใฎ State ใฏ็”Ÿใ็ถšใ‘ใฆใ„ใ‚‹ใ€‚
// ใงใฏใ€่ชฐใŒ Widget ใฎใƒฉใ‚คใƒ•ใ‚ตใ‚คใ‚ฏใƒซใ‚’็ฎก็†ใ—ใฆใ„ใ‚‹ใฎใงใ—ใ‚‡ใ†ใ‹๏ผŸ ๐Ÿ‘‰ Element ใจใ„ใ†ใ‚‚ใฎใ€‚
// ๅ†…้ƒจ็š„ใซใฏ Widgetใƒ„ใƒชใƒผ ใจๅฏพใจใชใ‚‹ Elementใƒ„ใƒชใƒผ ใŒๆง‹็ฏ‰ใ•ใ‚Œใฆใ„ใพใ™ใ€‚
// (ๅ‚่€ƒ) https://docs.flutter.dev/resources/architectural-overview
// (2) Element ใฎๅฝนๅ‰ฒใฏ๏ผŸ
// ใƒปWidget ใจใใฎ็Šถๆ…‹ใฎใƒฉใ‚คใƒ•ใ‚ตใ‚คใ‚ฏใƒซ็ฎก็†
// ใƒปใƒ“ใƒซใƒ‰,ใƒชใƒ“ใƒซใƒ‰ใฎ็ฎก็†
// ใƒปWidget ใฎ่ฆชๅญ้–ขไฟ‚ใฎ็ฎก็†
// build ใƒกใ‚ฝใƒƒใƒ‰ใฎ BuildContext ใฏๅฎŸใฏ Element ใใฎใ‚‚ใฎใ ใฃใŸใ‚Šใ—ใพใ™ใ€‚
// (ๅ‚่€ƒ) https://zenn.dev/chooyan/books/934f823764db62/viewer/3d3f8e
// (3) Widget ใƒ„ใƒชใƒผใ‹ใ‚‰ใ‚ใ‚‹ Widget ใŒใ„ใชใใชใ‚‹ใจใ€ใใฎๅฏพใจใชใ‚‹ Element ใ‚‚็ ดๆฃ„ใ•ใ‚Œใ‚‹ใƒ‡ใƒข
final class PageB extends StatefulWidget {
const PageB({super.key});
@override
State<PageB> createState() => PageBState();
}
final class PageBState extends State<PageB> {
PageBState();
bool _flag = true;
@override
Widget build(BuildContext context) {
return Stack(
children: [
// (4) Switch ใง _flag ใŒ true/false ใจๅˆ‡ใ‚Šๆ›ฟใ‚ใ‚‹ใ‚ˆใ†ใซใชใฃใฆใ„ใพใ™ใ€‚
Switch(
value: _flag,
onChanged: (newValue) => setState(
() => _flag = newValue,
),
),
// (5) ใ“ใ‚Œใฏ[A]ใฎ Counter ใจๅŒใ˜ใ‚‚ใฎใ€‚ใƒœใ‚ฟใƒณๆŠผไธ‹ใง Countๅ€ค ใŒใ‚คใƒณใ‚ฏใƒชใƒกใƒณใƒˆใ€‚
// ใŸใ ใ€_flag ใŒ false ใซใชใ‚‹ใจ Widget ใƒ„ใƒชใƒผใ‹ใ‚‰ๆถˆใˆใ‚‹ใ‚ˆใ†ใซใ—ใฆใ‚ใ‚Šใพใ™ใ€‚
// ๐Ÿ‘‰ ๆถˆใˆใ‚‹ใจใจใ‚‚ใซ Element ใ‚‚็ ดๆฃ„ใ•ใ‚Œใ‚‹ใ€ใคใพใ‚Š State ใ‚‚็ ดๆฃ„ใ•ใ‚Œใ‚‹ใ€‚
if (_flag) const CounterWidget(),
// (6) ็Šถๆ…‹ใ‚’ไฟๆŒใ—ใŸใพใพ้ž่กจ็คบใซใ—ใŸใ„ๅ ดๅˆใฏ Visibility Widget ใ‚’ไฝฟใ„ใพใ—ใ‚‡ใ†ใ€‚
// Visibility(
// visible: _flag,
// maintainState: true, // ใ“ใฎใƒ•ใƒฉใ‚ฐใ‚’ true ใซใ™ใ‚‹ใ“ใจใง็Šถๆ…‹ใŒไฟๆŒใ•ใ‚Œใพใ™
// child: const CounterWidget(),
// ),
],
);
}
}
//================================================================================
// [C] Flutter Hooks ใฎๅŸบๆœฌ (useState)
//================================================================================
// (1) Flutter Hooks ใฏใ€ไธ€่จ€ใง่จ€ใ†ใจ StatefulWidget ใฎไปฃๆ›ฟใจใชใ‚‹ใ‚‚ใฎใงใ™ใ€‚
// ใคใพใ‚Šใ€Widget ใƒญใƒผใ‚ซใƒซใช็Šถๆ…‹ใฎ็ฎก็†ใ‚’่กŒใ†ใŸใ‚ใฎใ‚‚ใฎใงใ™ใ€‚
// StatefulWidget ใ‚ˆใ‚Šใ‚‚ใ‹ใชใ‚Šใ‚ทใƒณใƒ—ใƒซใซๅฎŸ่ฃ…ใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚
// ไพ‹ใจใ—ใฆ StatefulWidget ใงๅฎŸ่ฃ…ใ•ใ‚ŒใŸ Counter ใ‚’ Flutter Hooks ใซ็ฝฎใๆ›ใˆใฆใฟใพใ™ใ€‚
final class PageC extends StatelessWidget {
const PageC();
@override
Widget build(BuildContext context) {
return const Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('StatefulWidget'),
CounterStatefulWidget(),
SizedBox(height: 32),
Text('Flutter Hooks'),
CounterHookWidget(),
],
),
);
}
}
// (2) StatefulWidget ใฎไพ‹
final class CounterStatefulWidget extends StatefulWidget {
const CounterStatefulWidget({super.key});
@override
State<CounterStatefulWidget> createState() => CounterStatefulWidgetState();
}
final class CounterStatefulWidgetState extends State<CounterStatefulWidget> {
CounterStatefulWidgetState();
int _count = 0;
@override
void initState() => super.initState();
@override
Widget build(BuildContext context) {
return Column(children: [
Text('$_count'),
FilledButton(
onPressed: () => setState(() => _count++),
child: const Text('+'),
)
]);
}
}
// (3) Flutter Hooks ใฎไพ‹ใ€‚
// HookWidget ใ‚’็ถ™ๆ‰ฟใ—ใฆ Widget ใ‚’ๅฎš็พฉใ™ใ‚‹ใ ใ‘ใงใ™ใ€‚State ใฎๅฎš็พฉใŒไธ่ฆใ€‚
final class CounterHookWidget extends HookWidget {
const CounterHookWidget({super.key});
@override
Widget build(BuildContext context) {
// (4) build ใƒกใ‚ฝใƒƒใƒ‰ๅ†…ใง useState ใ‚’ไฝฟใฃใฆ็Šถๆ…‹ใ‚’ๅฎš็พฉใ—ใพใ™ใ€‚
// ๅˆๅ›žใƒ“ใƒซใƒ‰ๆ™‚ใฏๅผ•ๆ•ฐใงๆธกใ•ใ‚ŒใŸๅˆๆœŸๅ€คใจใชใ‚Šใพใ™ใ€‚
final count = useState<int>(0);
return Column(children: [
// (5) ็Šถๆ…‹ใฎๅ€คใ‚’ๅ‚็…งใ™ใ‚‹ใซใฏ value ใƒ•ใ‚ฃใƒผใƒซใƒ‰ใ‚’ๅ‚็…งใ—ใพใ™ใ€‚
Text('${count.value}'),
FilledButton(
// (6) ็Šถๆ…‹ใฎๅ€คใ‚’ๆ›ดๆ–ฐใ™ใ‚‹ใซใฏ value ใƒ•ใ‚ฃใƒผใƒซใƒ‰ใ‚’ๆ›ดๆ–ฐใ™ใ‚‹ใ ใ‘ใงใ™ใ€‚
// setState ใ—ใชใใฆใ‚‚ใƒชใƒ“ใƒซใƒ‰ใŒ็™บ็”Ÿใ—ใพใ™ใ€‚
onPressed: () => count.value++,
child: const Text('+'),
)
]);
}
}
// (7) ใชใœ Hooks ใจ่จ€ใ†ใฎใ‹๏ผŸ
// UI๏ผˆWidget๏ผ‰ใซ็Šถๆ…‹ใ‚’ใฒใฃใ‹ใ‘ใ‚‹๏ผˆใƒ•ใƒƒใ‚ฏใ™ใ‚‹๏ผ‰ใจใ„ใ†ๆ„ๅ‘ณใ‚‰ใ—ใ„ใงใ™ใ€‚
// ๅฎฃ่จ€็š„UI ใฎ็ฅ–ใงใ‚ใ‚‹ React ใƒ•ใƒฌใƒผใƒ ใƒฏใƒผใ‚ฏใŒๅ…ฌๅผใซๆไพ›ใ™ใ‚‹ๆฉŸ่ƒฝใ‚’ Flutter ใซใ‚‚ใฃใฆใใŸใ€‚
// (ๅ‚่€ƒ) https://ja.react.dev/reference/react/useState
// (8) useState ไปฅๅค–ใซใ‚‚ use~ ใจใ„ใ†ๅๅ‰ใงไพฟๅˆฉใชใƒ•ใƒƒใ‚ฏใŒ็”จๆ„ใ•ใ‚Œใฆใ„ใ‚‹ใ—ใ€
// ่‡ชๅˆ†ใง็‹ฌ่‡ชใฎใ‚ซใ‚นใ‚ฟใƒ ใƒ•ใƒƒใ‚ฏใ‚’ไฝœใ‚‹ใ“ใจใ‚‚ใงใใพใ™ใ€‚
// (ๅ‚่€ƒ) https://github.com/rrousselGit/flutter_hooks#existing-hooks
//================================================================================
// [D] Flutter Hooks ใฎๅŸบๆœฌ (useEffect)
//================================================================================
// (1) useEffect ใฏ Widget ใฎ็‰นๅฎšใฎใƒ“ใƒซใƒ‰ใฎใ‚ฟใ‚คใƒŸใƒณใ‚ฐใงๅ‡ฆ็†๏ผˆ= Effect๏ผ‰ใ‚’ๅฎŸ่กŒใ™ใ‚‹ใŸใ‚ใฎใ‚‚ใฎใงใ™ใ€‚
// ๆŒ‡ๅฎšใ™ใ‚‹ keys ใŒๅ‰ๅ›žใฎใƒ“ใƒซใƒ‰ๆ™‚ใ‹ใ‚‰ๅค‰ๅŒ–ใ—ใŸๆ™‚ใ ใ‘ Effect ใŒๅฎŸ่กŒใ•ใ‚Œใพใ™ใ€‚
// ๅˆๅ›žใƒ“ใƒซใƒ‰ๆ™‚ใ ใ‘ๅ‡ฆ็†ใ‚’ๅฎŸ่กŒใ—ใŸใ„ๆ™‚ใชใฉใงใ‚ˆใๅˆฉ็”จใ•ใ‚Œใพใ™๏ผˆStatefulWidgetใฎinitStateใฎไปฃๆ›ฟ๏ผ‰
final class PageD extends HookWidget {
const PageD({super.key});
@override
Widget build(BuildContext context) {
final count1 = useState<int>(0);
final count2 = useState<int>(0);
// (2) build ใƒกใ‚ฝใƒƒใƒ‰ใฎไธญใง useEffect ใ‚’ๅ‘ผใณๅ‡บใ—ใพใ™ใ€‚
// ็‰นๅฎšใฎใƒ“ใƒซใƒ‰ใฎใ‚ฟใ‚คใƒŸใƒณใ‚ฐใง็ฌฌ1ๅผ•ๆ•ฐใซๆŒ‡ๅฎšใ—ใŸ Function ใŒๅฎŸ่กŒใ•ใ‚Œใพใ™ใ€‚
// ใ“ใ“ใงใฏ็ฌฌ2ๅผ•ๆ•ฐ keys ใŒ็ฉบใชใฎใงๅˆๅ›žใƒ“ใƒซใƒ‰ๆ™‚ใ ใ‘ๅฎŸ่กŒใ•ใ‚Œใพใ™ใ€‚
useEffect(() {
debugPrint('[PageD] useEffect');
return null;
}, const []);
// (3) keys ใซๆŒ‡ๅฎšใ•ใ‚ŒใŸ count1 ใŒๅค‰ๅŒ–ใ—ใŸๆ™‚ใ ใ‘ๅฎŸ่กŒใ•ใ‚Œใพใ™ใ€‚
useEffect(() {
debugPrint('[PageD] useEffect for count1 => ${count1.value}');
return null;
}, [count1.value]);
// (4) keys ใซๆŒ‡ๅฎšใ•ใ‚ŒใŸ count2 ใŒๅค‰ๅŒ–ใ—ใŸๆ™‚ใ ใ‘ๅฎŸ่กŒใ•ใ‚Œใพใ™ใ€‚
useEffect(() {
debugPrint('[PageD] useEffect for count2 => ${count2.value}');
return null;
}, [count2.value]);
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("Count 1 = ${count1.value}"),
FilledButton(
onPressed: () => count1.value++,
child: const Text('+'),
),
const SizedBox(height: 8),
Text("Count 2 = ${count2.value}"),
FilledButton(
onPressed: () => count2.value++,
child: const Text('+'),
),
const SizedBox(height: 8)
],
),
);
}
}
//================================================================================
// [E] Flutter Hooks ใฎๅŸบๆœฌ (use~Controller)
//================================================================================
// (1) use~Controller ใฏ Flutter ใฎ TextEditingController ใ‚„ AnimationController ใชใฉใ€
// UI ใ‚’ใ‚ณใƒณใƒˆใƒญใƒผใƒซใ™ใ‚‹ใŸใ‚ใซๆไพ›ใ•ใ‚Œใฆใ„ใ‚‹ Controller ใ‚’ๆ‰ฑใ„ใ‚„ใ™ใใ—ใฆใใ‚Œใพใ™ใ€‚
final class PageE extends HookWidget {
const PageE();
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: EdgeInsets.all(32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('StatefulWidget'),
TextFieldStatefulWidget(),
SizedBox(height: 32),
Text('Flutter Hooks'),
TextFieldHookWidget(),
],
),
),
);
}
}
// (2) StatefulWidget ใฎไพ‹
final class TextFieldStatefulWidget extends StatefulWidget {
const TextFieldStatefulWidget({super.key});
@override
State<TextFieldStatefulWidget> createState() =>
TextFieldStatefulWidgetState();
}
final class TextFieldStatefulWidgetState
extends State<TextFieldStatefulWidget> {
TextFieldStatefulWidgetState();
late final TextEditingController _controller;
@override
void initState() {
// (3) Controller ใฎ็”Ÿๆˆใฏ initState ใฎไธญใง
_controller = TextEditingController(text: 'initial text');
super.initState();
}
@override
void dispose() {
// (4) ไธ่ฆใซใชใฃใŸๆ™‚็‚นใง dispose ใƒกใ‚ฝใƒƒใƒ‰ใ‚’ๅ‘ผใ‚“ใงใ‚ใ’ใชใ‘ใ‚Œใฐใชใ‚Šใพใ›ใ‚“
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () => _controller.text = '',
),
),
);
}
}
// (3) HookWidget + useTextEditingController ใฎไพ‹
final class TextFieldHookWidget extends HookWidget {
const TextFieldHookWidget({super.key});
@override
Widget build(BuildContext context) {
// (4) build ใƒกใ‚ฝใƒƒใƒ‰ๅ†…ใง useTextEditingController ใ‚’ไฝฟใฃใฆ Controller ใ‚’ๅ–ๅพ—ใ—ใพใ™ใ€‚
// dispose ใจใ„ใฃใŸใƒฉใ‚คใƒ•ใ‚ตใ‚คใ‚ฏใƒซใฎ็ฎก็†ใฏๅ‹ๆ‰‹ใซใ‚„ใฃใฆใใ‚Œใ‚‹ใฎใงไธ่ฆใงใ™ใ€‚
final controller = useTextEditingController(text: 'initial text');
return TextField(
controller: controller,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () => controller.text = '',
),
),
);
}
}
//================================================================================
// [F] Riverpod ใฎๅ„ๆฉŸ่ƒฝ
//================================================================================
// ๅ…ฌๅผใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆ
// https://dartpad.dev/?id=aedf93fcc19ea97fc6b94622d53dc87a
//
// ไป•็ต„ใฟใ‹ใ‚‰็†่งฃใ™ใ‚‹ Riverpod / Riverpod ใƒใƒผใƒˆใ‚ทใƒผใƒˆ
// https://zenn.dev/chooyan/books/92a0a489f68233/viewer/overview
final class PageF extends StatelessWidget {
const PageF();
@override
Widget build(BuildContext context) {
return const Center(
child: Text('No contents'),
);
}
}
//================================================================================
// Common
//================================================================================
void main() => runApp(const App());
final class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) {
return ProviderScope(
child: MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.linear(2.0),
),
child: MaterialApp(
title: 'Flutter State Management Guide',
debugShowCheckedModeBanner: false,
theme: ThemeData(colorSchemeSeed: Colors.blue),
home: Scaffold(
appBar: AppBar(title: Text('Flutter State Management')),
body: ListView(children: items),
),
),
),
);
}
}
final class Item extends StatelessWidget {
Item(this.builder, this.title, {super.key});
final String title;
final WidgetBuilder builder;
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (c) => Scaffold(
appBar: AppBar(
title: Text(title),
),
body: builder(c),
),
),
),
);
}
}
final class Rainbow extends StatelessWidget {
const Rainbow({required this.child, super.key});
final Widget child;
@override
Widget build(BuildContext context) => RepaintBoundary(
key: super.key,
child: CustomPaint(
painter: _RepaintPainter(),
child: child,
),
);
}
final class _RepaintPainter extends CustomPainter {
_RepaintPainter();
final _num = math.Random().nextInt((1 << 31) - 1);
@override
void paint(Canvas canvas, Size size) {
int k = 0;
int r, g, b = 0;
double lum = 0.0;
do {
k += 1;
r = (_num * k * 64) % 255;
g = (_num * k * 128) % 255;
b = (_num * k * 192) % 255;
lum = 0.2126 * (r / 255.0) + 0.7152 * (g / 255.0) + 0.0722 * (b / 255.0);
} while (lum > 0.8);
canvas.drawRect(
Offset(1, 1) & Size(size.width - 2, size.height - 2),
Paint()
..color = Color.fromARGB(255, r, g, b)
..style = PaintingStyle.stroke
..strokeWidth = 2,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment