Unverified Commit d19c4434 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

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.
parent 78b45fb1
// 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'; ...@@ -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'; ...@@ -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; ...@@ -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; ...@@ -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 { ...@@ -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();
/// @override /// super.dispose();
/// void initState() { /// }
/// super.initState();
/// _controller = AnimationController(
/// duration: const Duration(seconds: 10),
/// vsync: this,
/// )..repeat();
/// }
///
/// @override
/// void dispose() {
/// _controller.dispose();
/// super.dispose();
/// }
/// ///
/// @override /// @override
/// Widget build(BuildContext context) { /// Widget build(BuildContext context) {
/// return AnimatedBuilder( /// return AnimatedBuilder(
/// animation: _controller, /// animation: _controller,
/// child: Container( /// child: Container(
/// width: 200.0, /// width: 200.0,
/// height: 200.0, /// height: 200.0,
/// color: Colors.green, /// color: Colors.green,
/// child: const Center( /// child: const Center(
/// child: Text('Wee'), /// child: Text('Whee!'),
/// ),
/// ), /// ),
/// 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment