setState、Provider、Riverpod
状态管理是Flutter应用开发的核心概念,用于管理应用中的数据和UI更新。
class CounterWidget extends StatefulWidget {
@override
State createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('计数: $_counter'),
ElevatedButton(
onPressed: _increment,
child: Text('增加'),
),
],
);
}
}
// 定义InheritedWidget
class CounterProvider extends InheritedWidget {
final int counter;
final Function() increment;
const CounterProvider({
Key? key,
required this.counter,
required this.increment,
required Widget child,
}) : super(key: key, child: child);
static CounterProvider? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
@override
bool updateShouldNotify(CounterProvider oldWidget) {
return counter != oldWidget.counter;
}
}
// 使用
class MyApp extends StatefulWidget {
@override
State createState() => _MyAppState();
}
class _MyAppState extends State {
int _counter = 0;
void _increment() {
setState(() => _counter++);
}
@override
Widget build(BuildContext context) {
return CounterProvider(
counter: _counter,
increment: _increment,
child: MaterialApp(
home: HomePage(),
),
);
}
}
// 子Widget访问数据
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = CounterProvider.of(context)!;
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('计数: ${provider.counter}'),
ElevatedButton(
onPressed: provider.increment,
child: Text('增加'),
),
],
),
),
);
}
}
1. 安装Provider
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
provider: ^6.0.0
2. 创建数据模型
import 'package:flutter/foundation.dart';
class CounterModel extends ChangeNotifier {
int _counter = 0;
int get counter => _counter;
void increment() {
_counter++;
notifyListeners(); // 通知监听者更新
}
void decrement() {
_counter--;
notifyListeners();
}
void reset() {
_counter = 0;
notifyListeners();
}
}
3. 提供Provider
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
),
);
}
// 多个Provider
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => CounterModel()),
ChangeNotifierProvider(create: (context) => UserModel()),
ChangeNotifierProvider(create: (context) => CartModel()),
],
child: MyApp(),
),
);
}
4. 消费Provider
// 方法1: Consumer
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Consumer(
builder: (context, counter, child) {
return Text(
'计数: ${counter.counter}',
style: TextStyle(fontSize: 32),
);
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
context.read().increment();
},
child: Text('增加'),
),
],
),
),
);
}
}
// 方法2: Provider.of
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of(context);
return Text('计数: ${counter.counter}');
}
}
// 方法3: context扩展方法
class CounterButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
context.read().increment();
},
child: Text('增加'),
);
}
}
// 商品模型
class Product {
final String id;
final String name;
final double price;
Product({required this.id, required this.name, required this.price});
}
// 购物车模型
class CartModel extends ChangeNotifier {
final List _items = [];
List get items => _items;
int get itemCount => _items.length;
double get totalPrice {
return _items.fold(0, (sum, item) => sum + item.price);
}
void addItem(Product product) {
_items.add(product);
notifyListeners();
}
void removeItem(String productId) {
_items.removeWhere((item) => item.id == productId);
notifyListeners();
}
void clear() {
_items.clear();
notifyListeners();
}
}
// 使用购物车
class ProductListPage extends StatelessWidget {
final List products = [
Product(id: '1', name: '商品1', price: 99.9),
Product(id: '2', name: '商品2', price: 199.9),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('商品列表'),
actions: [
Consumer(
builder: (context, cart, child) {
return Stack(
children: [
IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CartPage()),
);
},
),
if (cart.itemCount > 0)
Positioned(
right: 8,
top: 8,
child: Container(
padding: EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(10),
),
constraints: BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Text(
'${cart.itemCount}',
style: TextStyle(
color: Colors.white,
fontSize: 10,
),
textAlign: TextAlign.center,
),
),
),
],
);
},
),
],
),
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
title: Text(product.name),
subtitle: Text('¥${product.price}'),
trailing: ElevatedButton(
onPressed: () {
context.read().addItem(product);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('已添加到购物车')),
);
},
child: Text('加入购物车'),
),
);
},
),
);
}
}
1. 安装Riverpod
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.0.0
2. 定义Provider
import 'package:flutter_riverpod/flutter_riverpod.dart';
// StateProvider - 简单状态
final counterProvider = StateProvider((ref) => 0);
// StateNotifierProvider - 复杂状态
class CounterNotifier extends StateNotifier {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
void reset() => state = 0;
}
final counterNotifierProvider = StateNotifierProvider(
(ref) => CounterNotifier(),
);
3. 使用Riverpod
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class HomePage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('计数: $counter', style: TextStyle(fontSize: 32)),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Text('增加'),
),
],
),
),
);
}
}