Add sample for InheritedNotifier, convert two others to DartPa… (#52349)
This adds a sample for InheritedNotifier, and converts a couple of other samples to be DartPad samples. I also added a new sample template stateful_widget_material_ticker, which adds a TickerProviderStateMixin to the state object so that animation controllers can be created there easily.
This commit is contained in:
parent
78b45fb1b2
commit
d19c44344b
@ -0,0 +1,35 @@
|
|||||||
|
// Flutter code sample for {{element}}
|
||||||
|
|
||||||
|
{{description}}
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
{{code-imports}}
|
||||||
|
|
||||||
|
void main() => runApp(new MyApp());
|
||||||
|
|
||||||
|
/// This Widget is the main application widget.
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
static const String _title = 'Flutter Code Sample';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
title: _title,
|
||||||
|
home: MyStatefulWidget(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{code-preamble}}
|
||||||
|
|
||||||
|
class MyStatefulWidget extends StatefulWidget {
|
||||||
|
MyStatefulWidget({Key key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin {
|
||||||
|
{{code}}
|
||||||
|
}
|
@ -38,9 +38,10 @@ import 'observer_list.dart';
|
|||||||
///
|
///
|
||||||
/// * [AnimatedBuilder], a widget that uses a builder callback to rebuild
|
/// * [AnimatedBuilder], a widget that uses a builder callback to rebuild
|
||||||
/// whenever a given [Listenable] triggers its notifications. This widget is
|
/// whenever a given [Listenable] triggers its notifications. This widget is
|
||||||
/// commonly used with [Animation] subclasses, wherein its name. It is a
|
/// commonly used with [Animation] subclasses, hence its name, but is by no
|
||||||
/// subclass of [AnimatedWidget], which can be used to create widgets that
|
/// means limited to animations, as it can be used with any [Listenable]. It
|
||||||
/// are driven from a [Listenable].
|
/// is a subclass of [AnimatedWidget], which can be used to create widgets
|
||||||
|
/// that are driven from a [Listenable].
|
||||||
/// * [ValueListenableBuilder], a widget that uses a builder callback to
|
/// * [ValueListenableBuilder], a widget that uses a builder callback to
|
||||||
/// rebuild whenever a [ValueListenable] object triggers its notifications,
|
/// rebuild whenever a [ValueListenable] object triggers its notifications,
|
||||||
/// providing the builder with the value of the object.
|
/// providing the builder with the value of the object.
|
||||||
|
@ -28,6 +28,93 @@ import 'framework.dart';
|
|||||||
/// changed. When it returns true, the dependents are marked as needing to be
|
/// changed. When it returns true, the dependents are marked as needing to be
|
||||||
/// rebuilt this frame.
|
/// rebuilt this frame.
|
||||||
///
|
///
|
||||||
|
/// {@tool dartpad --template=stateful_widget_material_ticker}
|
||||||
|
///
|
||||||
|
/// This example shows three spinning squares that use the value of the notifier
|
||||||
|
/// on an ancestor [InheritedNotifier] (`SpinModel`) to give them their
|
||||||
|
/// rotation. The [InheritedNotifier] doesn't need to know about the children,
|
||||||
|
/// and the `notifier` argument doesn't need to be an animation controller, it
|
||||||
|
/// can be anything that implements [Listenable] (like a [ChangeNotifier]).
|
||||||
|
///
|
||||||
|
/// The `SpinModel` class could just as easily listen to another object (say, a
|
||||||
|
/// separate object that keeps the value of an input or data model value) that
|
||||||
|
/// is a [Listenable], and get the value from that. The descendants also don't
|
||||||
|
/// need to have an instance of the [InheritedNotifier] in order to use it, they
|
||||||
|
/// just need to know that there is one in their ancestry. This can help with
|
||||||
|
/// decoupling widgets from their models.
|
||||||
|
///
|
||||||
|
/// ```dart imports
|
||||||
|
/// import 'dart:math' as math;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```dart preamble
|
||||||
|
/// class SpinModel extends InheritedNotifier<AnimationController> {
|
||||||
|
/// SpinModel({
|
||||||
|
/// Key key,
|
||||||
|
/// AnimationController notifier,
|
||||||
|
/// Widget child,
|
||||||
|
/// }) : super(key: key, notifier: notifier, child: child);
|
||||||
|
///
|
||||||
|
/// static double of(BuildContext context) {
|
||||||
|
/// return context.dependOnInheritedWidgetOfExactType<SpinModel>().notifier.value;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// class Spinner extends StatelessWidget {
|
||||||
|
/// const Spinner();
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return Transform.rotate(
|
||||||
|
/// angle: SpinModel.of(context) * 2.0 * math.pi,
|
||||||
|
/// child: Container(
|
||||||
|
/// width: 100,
|
||||||
|
/// height: 100,
|
||||||
|
/// color: Colors.green,
|
||||||
|
/// child: const Center(
|
||||||
|
/// child: Text('Whee!'),
|
||||||
|
/// ),
|
||||||
|
/// ),
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// AnimationController _controller;
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// void initState() {
|
||||||
|
/// super.initState();
|
||||||
|
/// _controller = AnimationController(
|
||||||
|
/// duration: const Duration(seconds: 10),
|
||||||
|
/// vsync: this,
|
||||||
|
/// )..repeat();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// void dispose() {
|
||||||
|
/// _controller.dispose();
|
||||||
|
/// super.dispose();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return SpinModel(
|
||||||
|
/// notifier: _controller,
|
||||||
|
/// child: Row(
|
||||||
|
/// mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
/// children: const <Widget>[
|
||||||
|
/// Spinner(),
|
||||||
|
/// Spinner(),
|
||||||
|
/// Spinner(),
|
||||||
|
/// ],
|
||||||
|
/// ),
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// {@end-tool}
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [Animation], an implementation of [Listenable] that ticks each frame to
|
/// * [Animation], an implementation of [Listenable] that ticks each frame to
|
||||||
|
@ -23,41 +23,16 @@ export 'package:flutter/rendering.dart' show RelativeRect;
|
|||||||
/// [AnimatedWidget] is most useful for widgets that are otherwise stateless. To
|
/// [AnimatedWidget] is most useful for widgets that are otherwise stateless. To
|
||||||
/// use [AnimatedWidget], simply subclass it and implement the build function.
|
/// use [AnimatedWidget], simply subclass it and implement the build function.
|
||||||
///
|
///
|
||||||
///{@tool snippet}
|
///{@tool dartpad --template=stateful_widget_material_ticker}
|
||||||
///
|
///
|
||||||
/// This code defines a widget called `Spinner` that spins a green square
|
/// This code defines a widget called `Spinner` that spins a green square
|
||||||
/// continually. It is built with an [AnimatedWidget].
|
/// continually. It is built with an [AnimatedWidget].
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart imports
|
||||||
/// class Spinner extends StatefulWidget {
|
/// import 'dart:math' as math;
|
||||||
/// @override
|
/// ```
|
||||||
/// _SpinnerState createState() => _SpinnerState();
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// class _SpinnerState extends State<Spinner> with TickerProviderStateMixin {
|
|
||||||
/// AnimationController _controller;
|
|
||||||
///
|
|
||||||
/// @override
|
|
||||||
/// void initState() {
|
|
||||||
/// super.initState();
|
|
||||||
/// _controller = AnimationController(
|
|
||||||
/// duration: const Duration(seconds: 10),
|
|
||||||
/// vsync: this,
|
|
||||||
/// )..repeat();
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// @override
|
|
||||||
/// void dispose() {
|
|
||||||
/// _controller.dispose();
|
|
||||||
/// super.dispose();
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// @override
|
|
||||||
/// Widget build(BuildContext context) {
|
|
||||||
/// return SpinningContainer(controller: _controller);
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
///
|
||||||
|
/// ```dart preamble
|
||||||
/// class SpinningContainer extends AnimatedWidget {
|
/// class SpinningContainer extends AnimatedWidget {
|
||||||
/// const SpinningContainer({Key key, AnimationController controller})
|
/// const SpinningContainer({Key key, AnimationController controller})
|
||||||
/// : super(key: key, listenable: controller);
|
/// : super(key: key, listenable: controller);
|
||||||
@ -73,6 +48,30 @@ export 'package:flutter/rendering.dart' show RelativeRect;
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// AnimationController _controller;
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// void initState() {
|
||||||
|
/// super.initState();
|
||||||
|
/// _controller = AnimationController(
|
||||||
|
/// duration: const Duration(seconds: 10),
|
||||||
|
/// vsync: this,
|
||||||
|
/// )..repeat();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// void dispose() {
|
||||||
|
/// _controller.dispose();
|
||||||
|
/// super.dispose();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return SpinningContainer(controller: _controller);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
///
|
///
|
||||||
/// For more complex case involving additional state, consider using
|
/// For more complex case involving additional state, consider using
|
||||||
@ -1035,63 +1034,57 @@ class DefaultTextStyleTransition extends AnimatedWidget {
|
|||||||
/// Using this pre-built child is entirely optional, but can improve
|
/// Using this pre-built child is entirely optional, but can improve
|
||||||
/// performance significantly in some cases and is therefore a good practice.
|
/// performance significantly in some cases and is therefore a good practice.
|
||||||
///
|
///
|
||||||
/// {@tool snippet}
|
/// {@tool dartpad --template=stateful_widget_material_ticker}
|
||||||
///
|
///
|
||||||
/// This code defines a widget called `Spinner` that spins a green square
|
/// This code defines a widget that spins a green square continually. It is
|
||||||
/// continually. It is built with an [AnimatedBuilder] and makes use of the
|
/// built with an [AnimatedBuilder] and makes use of the [child] feature to
|
||||||
/// [child] feature to avoid having to rebuild the [Container] each time. The
|
/// avoid having to rebuild the [Container] each time.
|
||||||
/// resulting animation is shown below the code.
|
///
|
||||||
|
/// ```dart imports
|
||||||
|
/// import 'dart:math' as math;
|
||||||
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// class Spinner extends StatefulWidget {
|
/// AnimationController _controller;
|
||||||
/// @override
|
///
|
||||||
/// _SpinnerState createState() => _SpinnerState();
|
/// @override
|
||||||
|
/// void initState() {
|
||||||
|
/// super.initState();
|
||||||
|
/// _controller = AnimationController(
|
||||||
|
/// duration: const Duration(seconds: 10),
|
||||||
|
/// vsync: this,
|
||||||
|
/// )..repeat();
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// class _SpinnerState extends State<Spinner> with SingleTickerProviderStateMixin {
|
/// @override
|
||||||
/// AnimationController _controller;
|
/// void dispose() {
|
||||||
|
/// _controller.dispose();
|
||||||
|
/// super.dispose();
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// @override
|
/// @override
|
||||||
/// void initState() {
|
/// Widget build(BuildContext context) {
|
||||||
/// super.initState();
|
/// return AnimatedBuilder(
|
||||||
/// _controller = AnimationController(
|
/// animation: _controller,
|
||||||
/// duration: const Duration(seconds: 10),
|
/// child: Container(
|
||||||
/// vsync: this,
|
/// width: 200.0,
|
||||||
/// )..repeat();
|
/// height: 200.0,
|
||||||
/// }
|
/// color: Colors.green,
|
||||||
///
|
/// child: const Center(
|
||||||
/// @override
|
/// child: Text('Whee!'),
|
||||||
/// void dispose() {
|
|
||||||
/// _controller.dispose();
|
|
||||||
/// super.dispose();
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// @override
|
|
||||||
/// Widget build(BuildContext context) {
|
|
||||||
/// return AnimatedBuilder(
|
|
||||||
/// animation: _controller,
|
|
||||||
/// child: Container(
|
|
||||||
/// width: 200.0,
|
|
||||||
/// height: 200.0,
|
|
||||||
/// color: Colors.green,
|
|
||||||
/// child: const Center(
|
|
||||||
/// child: Text('Wee'),
|
|
||||||
/// ),
|
|
||||||
/// ),
|
/// ),
|
||||||
/// builder: (BuildContext context, Widget child) {
|
/// ),
|
||||||
/// return Transform.rotate(
|
/// builder: (BuildContext context, Widget child) {
|
||||||
/// angle: _controller.value * 2.0 * math.pi,
|
/// return Transform.rotate(
|
||||||
/// child: child,
|
/// angle: _controller.value * 2.0 * math.pi,
|
||||||
/// );
|
/// child: child,
|
||||||
/// },
|
/// );
|
||||||
/// );
|
/// },
|
||||||
/// }
|
/// );
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
///
|
///
|
||||||
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_builder.mp4}
|
|
||||||
///
|
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [TweenAnimationBuilder], which animates a property to a target value
|
/// * [TweenAnimationBuilder], which animates a property to a target value
|
||||||
|
Loading…
x
Reference in New Issue
Block a user