dart
class SimpleCounter extends StatefulWidget {
@override
_SimpleCounterState createState() => _SimpleCounterState();
}
class _SimpleCounterState extends State<SimpleCounter> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('$_counter'),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
} dart
class MyInheritedData extends InheritedWidget {
final int counter;
final Function() increment;
MyInheritedData({
required this.counter,
required this.increment,
required Widget child,
}) : super(child: child);
@override
bool updateShouldNotify(MyInheritedData oldWidget) {
return counter != oldWidget.counter;
}
static MyInheritedData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedData>()!;
}
}
// Использование в виджете
Text('${MyInheritedData.of(context).counter}') dart
class UserSettings extends ChangeNotifier {
String _username = 'Гость';
ThemeMode _themeMode = ThemeMode.light;
bool _notificationsEnabled = true;
String get username => _username;
ThemeMode get themeMode => _themeMode;
bool get notificationsEnabled => _notificationsEnabled;
void updateUsername(String newName) {
_username = newName;
notifyListeners(); // Уведомляем всех слушателей
}
void toggleTheme() {
_themeMode = _themeMode == ThemeMode.light
? ThemeMode.dark
: ThemeMode.light;
notifyListeners();
}
void toggleNotifications() {
_notificationsEnabled = !_notificationsEnabled;
notifyListeners();
}
}
// В приложении
ChangeNotifierProvider(
create: (_) => UserSettings(),
child: MyApp(),
); import 'package:flutter/foundation.dart';
// Используется ValueNotifier<int>, где хранимым значением является целое число.
// Это значение отслеживается и при его изменении автоматически уведомляются слушатели.
class CounterService extends ValueNotifier<int> {
// В конструкторе вызывается базовый конструктор ValueNotifier
// и задаётся начальное значение состояния (0).
CounterService() : super(0);
// Методы для изменения текущего состояния.
void increment() {
value++; // Изменение значения вызывает автоматическое уведомление слушателей.
}
void decrement() {
value--;
}
// Так как класс наследуется от ValueNotifier, вызов notifyListeners()
// осуществляется автоматически при обновлении value.
} import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_service.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// Используется ChangeNotifierProvider, так как ValueNotifier
// наследуется от ChangeNotifier и поддерживает механизм уведомлений.
return ChangeNotifierProvider(
create: (_) => CounterService(), // Инициализация экземпляра сервиса состояния.
child: const MaterialApp(
home: MyHomePage(),
),
);
}
} import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_service.dart';
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
// Используем Consumer.
// Consumer<T> отслеживает изменения в провайдере типа T (в данном случае CounterService).
// При изменении значения в CounterService перестраивается только участок интерфейса внутри билдера Consumer.
return Scaffold(
appBar: AppBar(title: const Text('Простой счетчик')),
body: Center(
child: Consumer<CounterService>(
builder: (_, counterService, __) {
// Внутри билдера доступен актуальный экземпляр CounterService.
// Получаем текущее значение и отображаем его.
return Text(
'${counterService.value}', // Текущее значение из ValueNotifier.
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () {
// Получаем сервис и вызываем метод изменения состояния.
// Provider.of с listen: false не вызывает перестроение текущего виджета,
// поскольку здесь требуется только выполнение действия.
Provider.of<CounterService>(context, listen: false).increment();
},
child: const Icon(Icons.add),
),
const SizedBox(height: 10),
FloatingActionButton(
onPressed: () {
Provider.of<CounterService>(context, listen: false).decrement();
},
child: const Icon(Icons.remove),
),
],
),
);
}
} import 'package:flutter/material.dart';
class ThemeService extends ValueNotifier<ThemeMode> {
ThemeService() : super(ThemeMode.light);
void toggleTheme() {
value = value == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
}
// Геттер для определения текущего режима темы.
bool get isDarkMode => value == ThemeMode.dark;
} void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ThemeService(), // Передаём ThemeService в дерево виджетов.
child: Consumer<ThemeService>(
// Consumer оборачивает MaterialApp, чтобы приложение обновлялось при смене темы.
builder: (context, themeService, child) {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: themeService.value, // Текущее значение темы из ThemeService.
home: const MyHomePage(),
);
},
),
);
}
} // ... inside MyHomePage's build method ...
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Кнопка смены темы.
FloatingActionButton(
onPressed: () {
Provider.of<ThemeService>(context, listen: false).toggleTheme();
},
child: const Icon(Icons.brightness_6),
),
// ... остальные кнопки ...
],
), dart
// todo_model.dart
class TodoItem {
final String id;
final String title;
bool completed;
TodoItem({
required this.id,
required this.title,
this.completed = false,
});
}
// todo_service.dart
import 'package:flutter/foundation.dart';
class TodoService extends ValueNotifier<List<TodoItem>> {
TodoService() : super([]);
void addTodo(String title) {
value = [
...value,
TodoItem(
id: DateTime.now().millisecondsSinceEpoch.toString(),
title: title,
),
];
}
void toggleTodo(String id) {
value = value.map((todo) {
if (todo.id == id) {
return TodoItem(
id: todo.id,
title: todo.title,
completed: !todo.completed,
);
}
return todo;
}).toList();
}
void removeTodo(String id) {
value = value.where((todo) => todo.id != id).toList();
}
int get pendingCount => value.where((todo) => !todo.completed).length;
int get completedCount => value.where((todo) => todo.completed).length;
} dart
// todo_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'todo_service.dart';
class TodoScreen extends StatelessWidget {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Список задач'),
actions: [
Consumer<TodoService>(
builder: (context, service, child) {
return Chip(
label: Text('${service.pendingCount}'),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
);
},
),
SizedBox(width: 10),
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Добавить новую задачу...',
border: OutlineInputBorder(),
),
),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: () {
if (_controller.text.isNotEmpty) {
Provider.of<TodoService>(context, listen: false)
.addTodo(_controller.text);
_controller.clear();
}
},
child: Text('Добавить'),
),
],
),
),
Expanded(
child: Consumer<TodoService>(
builder: (context, service, child) {
if (service.value.isEmpty) {
return Center(
child: Text(
'Нет задач',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
);
}
return ListView.builder(
itemCount: service.value.length,
itemBuilder: (context, index) {
final todo = service.value[index];
return ListTile(
leading: Checkbox(
value: todo.completed,
onChanged: (_) {
Provider.of<TodoService>(context, listen: false)
.toggleTodo(todo.id);
},
),
title: Text(
todo.title,
style: TextStyle(
decoration: todo.completed
? TextDecoration.lineThrough
: null,
color: todo.completed ? Colors.grey : null,
),
),
trailing: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () {
Provider.of<TodoService>(context, listen: false)
.removeTodo(todo.id);
},
),
);
},
);
},
),
),
],
),
);
}
} dart
// Вместо Consumer<UserProfile>:
Selector<UserProfile, String>(
selector: (context, profile) => profile.username,
builder: (context, username, child) {
return Text('Привет, $username!');
},
)
// Виджет перестроится только когда изменится username,
// даже если другие поля UserProfile изменятся. dart
Consumer<MyService>(
builder: (context, service, child) {
return Column(
children: [
// Эта часть не будет перестраиваться при каждом обновлении
child!,
// Эта часть перестраивается
Text('${service.value}'),
],
);
},
child: const HeaderWidget(), // Статический виджет
)