Skip to content

Commit

Permalink
Documentation improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Hixie committed Mar 17, 2023
1 parent 3dd3c02 commit 32b37ac
Show file tree
Hide file tree
Showing 23 changed files with 644 additions and 191 deletions.
52 changes: 26 additions & 26 deletions examples/api/lib/widgets/transitions/listenable_builder.1.dart
Expand Up @@ -2,12 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flutter code sample for a [ChangeNotifier] with a [ListenableBuilder].
// Flutter code sample for a [ValueNotifier] with a [ListenableBuilder].

import 'package:flutter/material.dart';

void main() { runApp(const ListenableBuilderExample()); }

class ListenableBuilderExample extends StatefulWidget {
const ListenableBuilderExample({super.key});

@override
State<ListenableBuilderExample> createState() => _ListenableBuilderExampleState();
}

class _ListenableBuilderExampleState extends State<ListenableBuilderExample> {
final ValueNotifier<int> _counter = ValueNotifier<int>(0);

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ListenableBuilder Example')),
body: CounterBody(counterValueNotifier: _counter),
floatingActionButton: FloatingActionButton(
onPressed: () => _counter.value++,
child: const Icon(Icons.add),
),
),
);
}
}

class CounterBody extends StatelessWidget {
const CounterBody({super.key, required this.counterValueNotifier});

Expand Down Expand Up @@ -35,28 +60,3 @@ class CounterBody extends StatelessWidget {
);
}
}

class ListenableBuilderExample extends StatefulWidget {
const ListenableBuilderExample({super.key});

@override
State<ListenableBuilderExample> createState() => _ListenableBuilderExampleState();
}

class _ListenableBuilderExampleState extends State<ListenableBuilderExample> {
final ValueNotifier<int> _counter = ValueNotifier<int>(0);

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ListenableBuilder Example')),
body: CounterBody(counterValueNotifier: _counter),
floatingActionButton: FloatingActionButton(
onPressed: () => _counter.value++,
child: const Icon(Icons.add),
),
),
);
}
}
72 changes: 72 additions & 0 deletions examples/api/lib/widgets/transitions/listenable_builder.2.dart
@@ -0,0 +1,72 @@
// 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.

// Flutter code sample for a [ChangeNotifier] with a [ListenableBuilder].

import 'package:flutter/material.dart';

void main() { runApp(const ListenableBuilderExample()); }

class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;

void increment() {
_count += 1;
notifyListeners();
}
}

class ListenableBuilderExample extends StatefulWidget {
const ListenableBuilderExample({super.key});

@override
State<ListenableBuilderExample> createState() => _ListenableBuilderExampleState();
}

class _ListenableBuilderExampleState extends State<ListenableBuilderExample> {
final CounterModel _counter = CounterModel();

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ListenableBuilder Example')),
body: CounterBody(counterNotifier: _counter),
floatingActionButton: FloatingActionButton(
onPressed: _counter.increment,
child: const Icon(Icons.add),
),
),
);
}
}

class CounterBody extends StatelessWidget {
const CounterBody({super.key, required this.counterNotifier});

final CounterModel counterNotifier;

@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Current counter value:'),
// Thanks to the ListenableBuilder, only the widget displaying the
// current count is rebuilt when counterValueNotifier notifies its
// listeners. The Text widget above and CounterBody itself aren't
// rebuilt.
ListenableBuilder(
listenable: counterNotifier,
builder: (BuildContext context, Widget? child) {
return Text('${counterNotifier.count}');
},
),
],
),
);
}
}
80 changes: 80 additions & 0 deletions examples/api/lib/widgets/transitions/listenable_builder.3.dart
@@ -0,0 +1,80 @@
// 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.

// Flutter code sample for a [ChangeNotifier] with a [ListenableBuilder].

import 'dart:math' as math;
import 'package:flutter/material.dart';

void main() { runApp(const ListenableBuilderExample()); }

class ListModel with ChangeNotifier {
final List<int> _values = <int>[];
List<int> get values => _values.toList(); // O(N), makes a new copy each time.

void add(int value) {
_values.add(value);
notifyListeners();
}
}

class ListenableBuilderExample extends StatefulWidget {
const ListenableBuilderExample({super.key});

@override
State<ListenableBuilderExample> createState() => _ListenableBuilderExampleState();
}

class _ListenableBuilderExampleState extends State<ListenableBuilderExample> {
final ListModel _listNotifier = ListModel();
final math.Random _random = math.Random(0); // fixed seed for reproducability

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ListenableBuilder Example')),
body: ListBody(listNotifier: _listNotifier),
floatingActionButton: FloatingActionButton(
onPressed: () => _listNotifier.add(_random.nextInt(1 << 32)), // 1 << 32 is the maximum supported value
child: const Icon(Icons.add),
),
),
);
}
}

class ListBody extends StatelessWidget {
const ListBody({super.key, required this.listNotifier});

final ListModel listNotifier;

@override
Widget build(BuildContext context) {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Text('Current values:'),
Expanded(
child: ListenableBuilder(
listenable: listNotifier,
builder: (BuildContext context, Widget? child) {
// We rebuild the ListView each time the list changes,
// so that the framework knows to update the rendering.
final List<int> values = listNotifier.values; // copy the list
return ListView.builder(
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text('${values[index]}'),
),
itemCount: values.length,
);
},
),
),
],
),
);
}
}
27 changes: 15 additions & 12 deletions packages/flutter/lib/src/animation/animation_controller.dart
Expand Up @@ -667,15 +667,18 @@ class AnimationController extends Animation<double>
/// and initial velocity.
///
/// If velocity is positive, the animation will complete, otherwise it will
/// dismiss.
/// dismiss. The velocity is specified in units per second. If the
/// [SemanticsBinding.disableAnimations] flag is set, the velocity is somewhat
/// arbitrarily multiplied by 200.
///
/// The [springDescription] parameter can be used to specify a custom [SpringType.criticallyDamped]
/// or [SpringType.overDamped] spring to drive the animation with. Defaults to null, which uses a
/// [SpringType.criticallyDamped] spring. See [SpringDescription.withDampingRatio] for how
/// to create a suitable [SpringDescription].
/// The [springDescription] parameter can be used to specify a custom
/// [SpringType.criticallyDamped] or [SpringType.overDamped] spring with which
/// to drive the animation. By default, a [SpringType.criticallyDamped] spring
/// is used. See [SpringDescription.withDampingRatio] for how to create a
/// suitable [SpringDescription].
///
/// The resulting spring simulation cannot be of type [SpringType.underDamped],
/// as this can lead to unexpected look of the produced animation.
/// The resulting spring simulation cannot be of type [SpringType.underDamped];
/// such a spring would oscillate rather than fling.
///
/// Returns a [TickerFuture] that completes when the animation is complete.
///
Expand All @@ -692,9 +695,7 @@ class AnimationController extends Animation<double>
if (SemanticsBinding.instance.disableAnimations) {
switch (behavior) {
case AnimationBehavior.normal:
// TODO(zanderso): determine a better process for setting velocity.
// the value below was arbitrarily chosen because it worked for the drawer widget.
scale = 200.0;
scale = 200.0; // This is arbitrary (it was chosen because it worked for the drawer widget).
break;
case AnimationBehavior.preserve:
break;
Expand All @@ -704,8 +705,10 @@ class AnimationController extends Animation<double>
..tolerance = _kFlingTolerance;
assert(
simulation.type != SpringType.underDamped,
'The resulting spring simulation is of type SpringType.underDamped.\n'
'This can lead to unexpected look of the animation, please adjust the springDescription parameter',
'The specified spring simulation is of type SpringType.underDamped.\n'
'An underdamped spring results in oscillation rather than a fling. '
'Consider specifying a different springDescription, or use animateWith() '
'with an explicit SpringSimulation if an underdamped spring is intentional.',
);
stop();
return _startSimulation(simulation);
Expand Down
37 changes: 36 additions & 1 deletion packages/flutter/lib/src/foundation/change_notifier.dart
Expand Up @@ -104,7 +104,29 @@ const String _flutterFoundationLibrary = 'package:flutter/foundation.dart';
/// It is O(1) for adding listeners and O(N) for removing listeners and dispatching
/// notifications (where N is the number of listeners).
///
/// {@macro flutter.flutter.ListenableBuilder.ChangeNotifier.rebuild}
/// ## Using ChangeNotifier subclasses for data models
///
/// A data structure can extend or mix in [ChangeNotifier] to implement the
/// [Listenable] interface and thus become usable with widgets that listen for
/// changes to [Listenable]s, such as [ListenableBuilder].
///
/// {@tool dartpad}
/// The following example implements a simple counter that utilizes a
/// [ListenableBuilder] to limit rebuilds to only the [Text] widget containing
/// the count. The current count is stored in a [ChangeNotifier] subclass, which
/// rebuilds the [ListenableBuilder]'s contents when its value is changed.
///
/// ** See code in examples/api/lib/widgets/transitions/listenable_builder.2.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// In this case, the [ChangeNotifier] subclass encapsulates a list, and notifies
/// the clients any time an item is added to the list. This example only supports
/// adding items; as an exercise, consider adding buttons to remove items from
/// the list as well.
///
/// ** See code in examples/api/lib/widgets/transitions/listenable_builder.3.dart **
/// {@end-tool}
///
/// See also:
///
Expand Down Expand Up @@ -466,6 +488,19 @@ class _MergingListenable extends Listenable {
/// When [value] is replaced with something that is not equal to the old
/// value as evaluated by the equality operator ==, this class notifies its
/// listeners.
///
/// ## Limitations
///
/// Because this class only notifies listeners when the [value]'s _identity_
/// changes, listeners will not be notified when mutable state within the
/// value itself changes.
///
/// For example, a `ValueNotifier<List<int>>` will not notify its listeners
/// when the _contents_ of the list are changed.
///
/// As a result, this class is best used with only immutable data types.
///
/// For mutable data types, consider extending [ChangeNotifier] directly.
class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
/// Creates a [ChangeNotifier] that wraps this value.
ValueNotifier(this._value) {
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/lib/src/foundation/diagnostics.dart
Expand Up @@ -2161,7 +2161,7 @@ class FlagProperty extends DiagnosticsProperty<bool> {
if (value == null || ((value ?? false) && ifTrue == null) || (!(value ?? true) && ifFalse == null)) {
// We are missing a description for the flag value so we need to show the
// flag name. The property will have DiagnosticLevel.hidden for this case
// so users will not see this the property in this case unless they are
// so users will not see this property in this case unless they are
// displaying hidden properties.
return true;
}
Expand Down Expand Up @@ -2378,7 +2378,7 @@ class ObjectFlagProperty<T> extends DiagnosticsProperty<T> {
if ((value != null && ifPresent == null) || (value == null && ifNull == null)) {
// We are missing a description for the flag value so we need to show the
// flag name. The property will have DiagnosticLevel.hidden for this case
// so users will not see this the property in this case unless they are
// so users will not see this property in this case unless they are
// displaying hidden properties.
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/lib/src/material/bottom_app_bar.dart
Expand Up @@ -81,8 +81,8 @@ class BottomAppBar extends StatefulWidget {
///
/// {@macro flutter.widgets.ProxyWidget.child}
///
/// Typically this the child will be a [Row], with the first child
/// being an [IconButton] with the [Icons.menu] icon.
/// Typically the child will be a [Row] whose first child
/// is an [IconButton] with the [Icons.menu] icon.
final Widget? child;

/// The amount of space to surround the child inside the bounds of the [BottomAppBar].
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter/lib/src/material/date_picker.dart
Expand Up @@ -2837,7 +2837,7 @@ class _InputDateRangePicker extends StatefulWidget {
/// {@macro flutter.widgets.editableText.autofocus}
final bool autofocus;

/// If true, this the date fields will validate and update their error text
/// If true, the date fields will validate and update their error text
/// immediately after every change. Otherwise, you must call
/// [_InputDateRangePickerState.validate] to validate.
final bool autovalidate;
Expand Down

0 comments on commit 32b37ac

Please sign in to comment.