mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

This extracts the sample code out from the API doc comments, and places them in separate files on disk, allowing running of the examples locally, testing them, and building of slightly larger examples.
220 lines
7.0 KiB
Dart
220 lines
7.0 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Template: dev/snippets/config/templates/stateful_widget_scaffold_center.tmpl
|
|
//
|
|
// Comment lines marked with "▼▼▼" and "▲▲▲" are used for authoring
|
|
// of samples, and may be ignored if you are just exploring the sample.
|
|
|
|
// Flutter code sample for Actions
|
|
//
|
|
//***************************************************************************
|
|
//* ▼▼▼▼▼▼▼▼ description ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
|
|
|
|
// This example creates a custom [Action] subclass `ModifyAction` for modifying
|
|
// a model, and another, `SaveAction` for saving it.
|
|
//
|
|
// This example demonstrates passing arguments to the [Intent] to be carried to
|
|
// the [Action]. Actions can get data either from their own construction (like
|
|
// the `model` in this example), or from the intent passed to them when invoked
|
|
// (like the increment `amount` in this example).
|
|
//
|
|
// This example also demonstrates how to use Intents to limit a widget's
|
|
// dependencies on its surroundings. The `SaveButton` widget defined in this
|
|
// example can invoke actions defined in its ancestor widgets, which can be
|
|
// customized to match the part of the widget tree that it is in. It doesn't
|
|
// need to know about the `SaveAction` class, only the `SaveIntent`, and it
|
|
// only needs to know about a value notifier, not the entire model.
|
|
|
|
//* ▲▲▲▲▲▲▲▲ description ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
|
|
//***************************************************************************
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
void main() => runApp(const MyApp());
|
|
|
|
/// This is the main application widget.
|
|
class MyApp extends StatelessWidget {
|
|
const MyApp({Key? key}) : super(key: key);
|
|
|
|
static const String _title = 'Flutter Code Sample';
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
title: _title,
|
|
home: Scaffold(
|
|
appBar: AppBar(title: const Text(_title)),
|
|
body: const Center(
|
|
child: MyStatefulWidget(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//* ▼▼▼▼▼▼▼▼ code-preamble ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
|
|
|
|
// A simple model class that notifies listeners when it changes.
|
|
class Model {
|
|
ValueNotifier<bool> isDirty = ValueNotifier<bool>(false);
|
|
ValueNotifier<int> data = ValueNotifier<int>(0);
|
|
|
|
int save() {
|
|
if (isDirty.value) {
|
|
print('Saved Data: ${data.value}');
|
|
isDirty.value = false;
|
|
}
|
|
return data.value;
|
|
}
|
|
|
|
void setValue(int newValue) {
|
|
isDirty.value = data.value != newValue;
|
|
data.value = newValue;
|
|
}
|
|
}
|
|
|
|
class ModifyIntent extends Intent {
|
|
const ModifyIntent(this.value);
|
|
|
|
final int value;
|
|
}
|
|
|
|
// An Action that modifies the model by setting it to the value that it gets
|
|
// from the Intent passed to it when invoked.
|
|
class ModifyAction extends Action<ModifyIntent> {
|
|
ModifyAction(this.model);
|
|
|
|
final Model model;
|
|
|
|
@override
|
|
void invoke(covariant ModifyIntent intent) {
|
|
model.setValue(intent.value);
|
|
}
|
|
}
|
|
|
|
// An intent for saving data.
|
|
class SaveIntent extends Intent {
|
|
const SaveIntent();
|
|
}
|
|
|
|
// An Action that saves the data in the model it is created with.
|
|
class SaveAction extends Action<SaveIntent> {
|
|
SaveAction(this.model);
|
|
|
|
final Model model;
|
|
|
|
@override
|
|
int invoke(covariant SaveIntent intent) => model.save();
|
|
}
|
|
|
|
class SaveButton extends StatefulWidget {
|
|
const SaveButton(this.valueNotifier, {Key? key}) : super(key: key);
|
|
|
|
final ValueNotifier<bool> valueNotifier;
|
|
|
|
@override
|
|
State<SaveButton> createState() => _SaveButtonState();
|
|
}
|
|
|
|
class _SaveButtonState extends State<SaveButton> {
|
|
int savedValue = 0;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: widget.valueNotifier,
|
|
builder: (BuildContext context, Widget? child) {
|
|
return TextButton.icon(
|
|
icon: const Icon(Icons.save),
|
|
label: Text('$savedValue'),
|
|
style: ButtonStyle(
|
|
foregroundColor: MaterialStateProperty.all<Color>(
|
|
widget.valueNotifier.value ? Colors.red : Colors.green,
|
|
),
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
savedValue = Actions.invoke(context, const SaveIntent())! as int;
|
|
});
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
//* ▲▲▲▲▲▲▲▲ code-preamble ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
|
|
//*****************************************************************************
|
|
|
|
/// This is the stateful widget that the main application instantiates.
|
|
class MyStatefulWidget extends StatefulWidget {
|
|
const MyStatefulWidget({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
|
|
}
|
|
|
|
/// This is the private State class that goes with MyStatefulWidget.
|
|
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
|
|
//********************************************************************
|
|
//* ▼▼▼▼▼▼▼▼ code ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
|
|
|
|
Model model = Model();
|
|
int count = 0;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Actions(
|
|
actions: <Type, Action<Intent>>{
|
|
ModifyIntent: ModifyAction(model),
|
|
SaveIntent: SaveAction(model),
|
|
},
|
|
child: Builder(
|
|
builder: (BuildContext context) {
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: <Widget>[
|
|
const Spacer(),
|
|
Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
IconButton(
|
|
icon: const Icon(Icons.exposure_plus_1),
|
|
onPressed: () {
|
|
Actions.invoke(context, ModifyIntent(++count));
|
|
},
|
|
),
|
|
AnimatedBuilder(
|
|
animation: model.data,
|
|
builder: (BuildContext context, Widget? child) {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Text('${model.data.value}',
|
|
style: Theme.of(context).textTheme.headline4),
|
|
);
|
|
}),
|
|
IconButton(
|
|
icon: const Icon(Icons.exposure_minus_1),
|
|
onPressed: () {
|
|
Actions.invoke(context, ModifyIntent(--count));
|
|
},
|
|
),
|
|
],
|
|
),
|
|
SaveButton(model.isDirty),
|
|
const Spacer(),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
//* ▲▲▲▲▲▲▲▲ code ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
|
|
//********************************************************************
|
|
|
|
}
|