Flutter - การจัดการของรัฐ
การจัดการสถานะในแอปพลิเคชันเป็นกระบวนการที่สำคัญและจำเป็นที่สุดกระบวนการหนึ่งในวงจรชีวิตของแอปพลิเคชัน
ให้เราพิจารณาแอปพลิเคชันตะกร้าสินค้าง่ายๆ
ผู้ใช้จะเข้าสู่ระบบโดยใช้ข้อมูลประจำตัวในแอปพลิเคชัน
เมื่อผู้ใช้เข้าสู่ระบบแอปพลิเคชันควรคงรายละเอียดผู้ใช้ที่ล็อกอินไว้ในทุกหน้าจอ
อีกครั้งเมื่อผู้ใช้เลือกผลิตภัณฑ์และบันทึกลงในรถเข็นข้อมูลรถเข็นควรคงอยู่ระหว่างหน้าจนกว่าผู้ใช้จะชำระเงินในรถเข็น
ผู้ใช้และข้อมูลรถเข็นของพวกเขาในทุกกรณีเรียกว่าสถานะของแอปพลิเคชันที่อินสแตนซ์นั้น
การจัดการสถานะสามารถแบ่งออกเป็นสองประเภทตามระยะเวลาที่สถานะเฉพาะอยู่ในแอปพลิเคชัน
Ephemeral- คงอยู่ไม่กี่วินาทีเช่นสถานะปัจจุบันของภาพเคลื่อนไหวหรือหน้าเดียวเช่นการให้คะแนนผลิตภัณฑ์ในปัจจุบัน Flutterรองรับผ่าน StatefulWidget
app state- สุดท้ายสำหรับแอปพลิเคชันทั้งหมดเช่นรายละเอียดผู้ใช้ที่เข้าสู่ระบบข้อมูลรถเข็น ฯลฯFlutterรองรับผ่าน scoped_model
การนำทางและการกำหนดเส้นทาง
ในแอปพลิเคชันใด ๆ การไปยังอีกหน้าหนึ่งจะกำหนดขั้นตอนการทำงานของแอปพลิเคชัน วิธีจัดการการนำทางของแอปพลิเคชันเรียกว่าการกำหนดเส้นทาง Flutter จัดเตรียมคลาสการกำหนดเส้นทางพื้นฐาน - MaterialPageRoute และสองวิธี - Navigator.push และ Navigator.pop เพื่อกำหนดขั้นตอนการทำงานของแอ็พพลิเคชัน
MaterialPageRoute
MaterialPageRoute เป็นวิดเจ็ตที่ใช้ในการแสดงผล UI โดยแทนที่หน้าจอทั้งหมดด้วยภาพเคลื่อนไหวเฉพาะแพลตฟอร์ม
MaterialPageRoute(builder: (context) => Widget())
ที่นี่ตัวสร้างจะยอมรับฟังก์ชันในการสร้างเนื้อหาโดยรองรับบริบทปัจจุบันของแอปพลิเคชัน
Navigation.push
Navigation.push ใช้เพื่อนำทางไปยังหน้าจอใหม่โดยใช้วิดเจ็ต MaterialPageRoute
Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );
Navigation.pop
Navigation.pop ใช้เพื่อนำทางไปยังหน้าจอก่อนหน้า
Navigator.push(context);
ให้เราสร้างแอปพลิเคชันใหม่เพื่อให้เข้าใจแนวคิดการนำทางได้ดีขึ้น
สร้างแอปพลิเคชัน Flutter ใหม่ใน Android studio product_nav_app
คัดลอกโฟลเดอร์ assets จาก product_nav_app ไปยัง product_state_app และเพิ่มเนื้อหาภายในไฟล์ pubspec.yaml
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
แทนที่รหัสเริ่มต้นเริ่มต้น (main.dart) ด้วยรหัสเริ่มต้นของเรา
import 'package:flutter/material.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,
),
home: MyHomePage(
title: 'Product state demo home page'
),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: Text('Hello World',)
),
);
}
}
ให้เราสร้างคลาสผลิตภัณฑ์เพื่อจัดระเบียบข้อมูลผลิตภัณฑ์
class Product {
final String name;
final String description;
final int price;
final String image;
Product(this.name, this.description, this.price, this.image);
}
ให้เราเขียนเมธอด getProducts ในคลาสผลิตภัณฑ์เพื่อสร้างเร็กคอร์ดผลิตภัณฑ์จำลองของเรา
static List<Product> getProducts() {
List<Product> items = <Product>[];
items.add(
Product(
"Pixel",
"Pixel is the most feature-full phone ever", 800,
"pixel.png"
)
);
items.add(
Product(
"Laptop",
"Laptop is most productive development tool",
2000, "
laptop.png"
)
);
items.add(
Product(
"Tablet",
"Tablet is the most useful device ever for meeting",
1500,
"tablet.png"
)
);
items.add(
Product(
"Pendrive",
"Pendrive is useful storage medium",
100,
"pendrive.png"
)
);
items.add(
Product(
"Floppy Drive",
"Floppy drive is useful rescue storage medium",
20,
"floppy.png"
)
);
return items;
}
import product.dart in main.dart
import 'Product.dart';
ให้เรารวมวิดเจ็ตใหม่ของเรา RatingBox
class RatingBox extends StatefulWidget {
@override
_RatingBoxState createState() =>_RatingBoxState();
}
class _RatingBoxState extends State<RatingBox> {
int _rating = 0;
void _setRatingAsOne() {
setState(() {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState(() {
_rating = 2;
});
}
void _setRatingAsThree() {
setState(() {
_rating = 3;
});
}
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 1?
Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)
),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 2?
Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)
),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 3 ?
Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)
),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
ให้เราปรับเปลี่ยนวิดเจ็ต ProductBox เพื่อทำงานกับคลาสผลิตภัณฑ์ใหม่ของเรา
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.item}) : super(key: key);
final Product item;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Text(this.item.description),
Text("Price: " + this.item.price.toString()),
RatingBox(),
],
)
)
)
]
),
)
);
}
}
ให้เราเขียนวิดเจ็ต MyHomePage ของเราใหม่เพื่อทำงานกับรุ่นผลิตภัณฑ์และแสดงรายการผลิตภัณฑ์ทั้งหมดโดยใช้ ListView
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
final items = Product.getProducts();
@override
Widget build(BuildContext context) {
return Scaffold( appBar: AppBar(title: Text("Product Navigation")),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ProductBox(item: items[index]),
onTap: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => ProductPage(item: items[index]),
),
);
},
);
},
));
}
}
ที่นี่เราได้ใช้ MaterialPageRoute เพื่อไปที่หน้ารายละเอียดผลิตภัณฑ์
ตอนนี้ให้เราเพิ่ม ProductPage เพื่อแสดงรายละเอียดสินค้า
class ProductPage extends StatelessWidget {
ProductPage({Key key, this.item}) : super(key: key);
final Product item;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.item.name),
),
body: Center(
child: Container(
padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset("assets/appimages/" + this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
this.item.name, style: TextStyle(
fontWeight: FontWeight.bold
)
),
Text(this.item.description),
Text("Price: " + this.item.price.toString()),
RatingBox(),
],
)
)
)
]
),
),
),
);
}
}
รหัสที่สมบูรณ์ของแอปพลิเคชันมีดังนี้ -
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class Product {
final String name;
final String description;
final int price;
final String image;
Product(this.name, this.description, this.price, this.image);
static List<Product> getProducts() {
List<Product> items = <Product>[];
items.add(
Product(
"Pixel",
"Pixel is the most featureful phone ever",
800,
"pixel.png"
)
);
items.add(
Product(
"Laptop",
"Laptop is most productive development tool",
2000,
"laptop.png"
)
);
items.add(
Product(
"Tablet",
"Tablet is the most useful device ever for meeting",
1500,
"tablet.png"
)
);
items.add(
Product(
"Pendrive",
"iPhone is the stylist phone ever",
100,
"pendrive.png"
)
);
items.add(
Product(
"Floppy Drive",
"iPhone is the stylist phone ever",
20,
"floppy.png"
)
);
items.add(
Product(
"iPhone",
"iPhone is the stylist phone ever",
1000,
"iphone.png"
)
);
return items;
}
}
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,
),
home: MyHomePage(title: 'Product Navigation demo home page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
final items = Product.getProducts();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ProductBox(item: items[index]),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductPage(item: items[index]),
),
);
},
);
},
)
);
}
}
class ProductPage extends StatelessWidget {
ProductPage({Key key, this.item}) : super(key: key);
final Product item;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.item.name),
),
body: Center(
child: Container(
padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset("assets/appimages/" + this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)),
Text(this.item.description),
Text("Price: " + this.item.price.toString()),
RatingBox(),
],
)
)
)
]
),
),
),
);
}
}
class RatingBox extends StatefulWidget {
@override
_RatingBoxState createState() => _RatingBoxState();
}
class _RatingBoxState extends State<RatingBox> {
int _rating = 0;
void _setRatingAsOne() {
setState(() {
_rating = 1;
});
}
void _setRatingAsTwo() {
setState(() {
_rating = 2;
});
}
void _setRatingAsThree() {
setState(() {
_rating = 3;
});
}
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 1 ? Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)
),
color: Colors.red[500],
onPressed: _setRatingAsOne,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 2 ?
Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)
),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 3 ?
Icon(
Icons.star,
size: _size,
)
: Icon(
Icons.star_border,
size: _size,
)
),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.item}) : super(key: key);
final Product item;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description),
Text("Price: " + this.item.price.toString()),
RatingBox(),
],
)
)
)
]
),
)
);
}
}
เรียกใช้แอปพลิเคชันและคลิกรายการผลิตภัณฑ์ใด ๆ จะแสดงหน้ารายละเอียดที่เกี่ยวข้อง เราสามารถย้ายไปที่โฮมเพจได้โดยคลิกปุ่มย้อนกลับ หน้ารายการสินค้าและหน้ารายละเอียดสินค้าของแอพพลิเคชั่นแสดงดังนี้ -