Unverified Commit dd7d4b95 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Fix docs and error messages for scroll directions + sample code (#123819)

Fix docs and error messages for scroll directions + sample code
parent e4e1444b
// 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 [AxisDirection]s.
import 'package:flutter/material.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyWidget(),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({ super.key });
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final List<String> _alphabet = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
final Widget _spacer = const SizedBox.square(dimension: 10);
AxisDirection _axisDirection = AxisDirection.down;
Widget _getArrows() {
final Widget arrow;
switch(_axisDirection) {
case AxisDirection.up:
arrow = const Icon(Icons.arrow_upward_rounded);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.down:
arrow = const Icon(Icons.arrow_downward_rounded);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.left:
arrow = const Icon(Icons.arrow_back_rounded);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.right:
arrow = const Icon(Icons.arrow_forward_rounded);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
}
}
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
if (axisDirection != null && axisDirection != _axisDirection) {
setState(() {
// Respond to change in axis direction.
_axisDirection = axisDirection;
});
}
}
Widget _getLeading() {
return Container(
color: Colors.blue[100],
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(axisDirectionToAxis(_axisDirection).toString()),
_spacer,
Text(_axisDirection.toString()),
_spacer,
const Text('GrowthDirection.forward'),
_spacer,
_getArrows(),
],
),
);
}
Widget _getRadioRow() {
return DefaultTextStyle(
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
child: RadioTheme(
data: RadioThemeData(
fillColor: MaterialStateProperty.all<Color>(Colors.white),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Radio<AxisDirection>(
value: AxisDirection.up,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('up'),
_spacer,
Radio<AxisDirection>(
value: AxisDirection.down,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('down'),
_spacer,
Radio<AxisDirection>(
value: AxisDirection.left,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('left'),
_spacer,
Radio<AxisDirection>(
value: AxisDirection.right,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('right'),
_spacer,
],
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AxisDirections'),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(50),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: _getRadioRow(),
),
),
),
// Also works for ListView.builder, which creates a SliverList for itself.
// A CustomScrollView allows multiple slivers to be composed together.
body: CustomScrollView(
// This method is available to conveniently determine if an scroll
// view is reversed by its AxisDirection.
reverse: axisDirectionIsReversed(_axisDirection),
// This method is available to conveniently convert an AxisDirection
// into its Axis.
scrollDirection: axisDirectionToAxis(_axisDirection),
slivers: <Widget>[
SliverList.builder(
itemCount: 27,
itemBuilder: (BuildContext context, int index) {
final Widget child;
if (index == 0) {
child = _getLeading();
} else {
child = Container(
color: index.isEven ? Colors.amber[100] : Colors.amberAccent,
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(_alphabet[index - 1])),
);
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: child,
);
}
),
],
),
);
}
}
// 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 [GrowthDirection]s.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyWidget(),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({ super.key });
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final List<String> _alphabet = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
final Widget _spacer = const SizedBox.square(dimension: 10);
final UniqueKey _center = UniqueKey();
AxisDirection _axisDirection = AxisDirection.down;
Widget _getArrows(AxisDirection axisDirection) {
final Widget arrow;
switch(axisDirection) {
case AxisDirection.up:
arrow = const Icon(Icons.arrow_upward_rounded);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.down:
arrow = const Icon(Icons.arrow_downward_rounded);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.left:
arrow = const Icon(Icons.arrow_back_rounded);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.right:
arrow = const Icon(Icons.arrow_forward_rounded);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
}
}
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
if (axisDirection != null && axisDirection != _axisDirection) {
setState(() {
// Respond to change in axis direction.
_axisDirection = axisDirection;
});
}
}
Widget _getLeading(SliverConstraints constraints, bool isForward) {
return Container(
color: isForward ? Colors.orange[300] : Colors.green[400],
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(constraints.axis.toString()),
_spacer,
Text(constraints.axisDirection.toString()),
_spacer,
Text(constraints.growthDirection.toString()),
_spacer,
_getArrows(isForward
? _axisDirection
// This method is available to conveniently flip an AxisDirection
// into its opposite direction.
: flipAxisDirection(_axisDirection),
),
],
),
);
}
Widget _getRadioRow() {
return DefaultTextStyle(
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
child: RadioTheme(
data: RadioThemeData(
fillColor: MaterialStateProperty.all<Color>(Colors.white),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Radio<AxisDirection>(
value: AxisDirection.up,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('up'),
_spacer,
Radio<AxisDirection>(
value: AxisDirection.down,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('down'),
_spacer,
Radio<AxisDirection>(
value: AxisDirection.left,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('left'),
_spacer,
Radio<AxisDirection>(
value: AxisDirection.right,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('right'),
_spacer,
],
),
),
),
);
}
Widget _getList({ required bool isForward }) {
// The SliverLayoutBuilder is not necessary, and is here to allow us to see
// the SliverConstraints & directional information that is provided to the
// SliverList when laying out.
return SliverLayoutBuilder(
builder: (BuildContext context, SliverConstraints constraints) {
return SliverList.builder(
itemCount: 27,
itemBuilder: (BuildContext context, int index) {
final Widget child;
if (index == 0) {
child = _getLeading(constraints, isForward);
} else {
child = Container(
color: isForward
? (index.isEven ? Colors.amber[100] : Colors.amberAccent)
: (index.isEven ? Colors.green[100] : Colors.lightGreen),
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(_alphabet[index - 1])),
);
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: child,
);
},
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('GrowthDirections'),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(50),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: _getRadioRow(),
),
),
),
body: CustomScrollView(
// This method is available to conveniently determine if an scroll
// view is reversed by its AxisDirection.
reverse: axisDirectionIsReversed(_axisDirection),
// This method is available to conveniently convert an AxisDirection
// into its Axis.
scrollDirection: axisDirectionToAxis(_axisDirection),
// Places the leading edge of the center sliver in the middle of the
// viewport. Changing this value between 0.0 (the default) and 1.0
// changes the position of the inflection point between GrowthDirections
// in the viewport when the slivers are laid out.
anchor: 0.5,
center: _center,
slivers: <Widget>[
_getList(isForward: false),
SliverToBoxAdapter(
// This sliver will be located at the anchor. The scroll position
// will progress in either direction from this point.
key: _center,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Center(child: Text('0', style: TextStyle(fontWeight: FontWeight.bold))),
),
),
_getList(isForward: true),
],
),
);
}
}
// 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 [ScrollDirection].
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyWidget(),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({ super.key });
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final List<String> alphabet = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
final Widget spacer = const SizedBox.square(dimension: 10);
ScrollDirection scrollDirection = ScrollDirection.idle;
AxisDirection _axisDirection = AxisDirection.down;
Widget _getArrows() {
final Widget arrow;
switch(_axisDirection) {
case AxisDirection.up:
arrow = const Icon(Icons.arrow_upward_rounded);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.down:
arrow = const Icon(Icons.arrow_downward_rounded);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.left:
arrow = const Icon(Icons.arrow_back_rounded);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
case AxisDirection.right:
arrow = const Icon(Icons.arrow_forward_rounded);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ arrow, arrow ],
);
}
}
void _onAxisDirectionChanged(AxisDirection? axisDirection) {
if (axisDirection != null && axisDirection != _axisDirection) {
setState(() {
// Respond to change in axis direction.
_axisDirection = axisDirection;
});
}
}
Widget _getLeading() {
return Container(
color: Colors.blue[100],
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(axisDirectionToAxis(_axisDirection).toString()),
spacer,
Text(_axisDirection.toString()),
spacer,
const Text('GrowthDirection.forward'),
spacer,
Text(scrollDirection.toString()),
spacer,
_getArrows(),
],
),
);
}
Widget _getRadioRow() {
return DefaultTextStyle(
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
child: RadioTheme(
data: RadioThemeData(
fillColor: MaterialStateProperty.all<Color>(Colors.white),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Radio<AxisDirection>(
value: AxisDirection.up,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('up'),
spacer,
Radio<AxisDirection>(
value: AxisDirection.down,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('down'),
spacer,
Radio<AxisDirection>(
value: AxisDirection.left,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('left'),
spacer,
Radio<AxisDirection>(
value: AxisDirection.right,
groupValue: _axisDirection,
onChanged: _onAxisDirectionChanged,
),
const Text('right'),
spacer,
],
),
),
),
);
}
bool _handleNotification(UserScrollNotification notification) {
if (notification.direction != scrollDirection) {
setState((){
scrollDirection = notification.direction;
});
}
return false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('ScrollDirections'),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(50),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: _getRadioRow(),
),
),
),
body: NotificationListener<UserScrollNotification>(
onNotification: _handleNotification,
// Also works for ListView.builder, which creates a SliverList for itself.
// A CustomScrollView allows multiple slivers to be composed together.
child: CustomScrollView(
// This method is available to conveniently determine if an scroll
// view is reversed by its AxisDirection.
reverse: axisDirectionIsReversed(_axisDirection),
// This method is available to conveniently convert an AxisDirection
// into its Axis.
scrollDirection: axisDirectionToAxis(_axisDirection),
slivers: <Widget>[
SliverList.builder(
itemCount: 27,
itemBuilder: (BuildContext context, int index) {
final Widget child;
if (index == 0) {
child = _getLeading();
} else {
child = Container(
color: index.isEven ? Colors.amber[100] : Colors.amberAccent,
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(alphabet[index - 1])),
);
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: child,
);
}
),
],
),
),
);
}
}
// 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.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_api_samples/painting/axis_direction/axis_direction.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Example app has radio buttons to toggle AxisDirection', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ExampleApp(),
);
expect(find.byType(Radio<AxisDirection>), findsNWidgets(4));
final RenderViewport viewport = tester.renderObject(find.byType(Viewport));
expect(find.text('AxisDirection.down'), findsOneWidget);
expect(find.text('Axis.vertical'), findsOneWidget);
expect(find.text('GrowthDirection.forward'), findsOneWidget);
expect(find.byIcon(Icons.arrow_downward_rounded), findsNWidgets(2));
expect(viewport.axisDirection, AxisDirection.down);
await tester.tap(
find.byWidgetPredicate((Widget widget) {
return widget is Radio<AxisDirection> && widget.value == AxisDirection.up;
})
);
await tester.pumpAndSettle();
expect(find.text('AxisDirection.up'), findsOneWidget);
expect(find.text('Axis.vertical'), findsOneWidget);
expect(find.text('GrowthDirection.forward'), findsOneWidget);
expect(find.byIcon(Icons.arrow_upward_rounded), findsNWidgets(2));
expect(viewport.axisDirection, AxisDirection.up);
});
}
// 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.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_api_samples/rendering/growth_direction/growth_direction.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Example app has GrowthDirections represented', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ExampleApp(),
);
final RenderViewport viewport = tester.renderObject(find.byType(Viewport));
expect(find.text('AxisDirection.down'), findsNWidgets(2));
expect(find.text('Axis.vertical'), findsNWidgets(2));
expect(find.text('GrowthDirection.forward'), findsOneWidget);
expect(find.text('GrowthDirection.reverse'), findsOneWidget);
expect(find.byIcon(Icons.arrow_upward_rounded), findsNWidgets(2));
expect(find.byIcon(Icons.arrow_downward_rounded), findsNWidgets(2));
expect(viewport.axisDirection, AxisDirection.down);
expect(viewport.anchor, 0.5);
expect(viewport.center, isNotNull);
await tester.tap(
find.byWidgetPredicate((Widget widget) {
return widget is Radio<AxisDirection> && widget.value == AxisDirection.up;
})
);
await tester.pumpAndSettle();
expect(find.text('AxisDirection.up'), findsNWidgets(2));
expect(find.text('Axis.vertical'), findsNWidgets(2));
expect(find.text('GrowthDirection.forward'), findsOneWidget);
expect(find.text('GrowthDirection.reverse'), findsOneWidget);
expect(find.byIcon(Icons.arrow_upward_rounded), findsNWidgets(2));
expect(find.byIcon(Icons.arrow_downward_rounded), findsNWidgets(2));
expect(viewport.axisDirection, AxisDirection.up);
});
}
// 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.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_api_samples/rendering/scroll_direction/scroll_direction.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Example app has ScrollDirection represented', (WidgetTester tester) async {
await tester.pumpWidget(
const example.ExampleApp(),
);
expect(find.byType(Radio<AxisDirection>), findsNWidgets(4));
final RenderViewport viewport = tester.renderObject(find.byType(Viewport));
expect(find.text('AxisDirection.down'), findsOneWidget);
expect(find.text('Axis.vertical'), findsOneWidget);
expect(find.text('GrowthDirection.forward'), findsOneWidget);
expect(find.text('ScrollDirection.idle'), findsOneWidget);
expect(find.byIcon(Icons.arrow_downward_rounded), findsNWidgets(2));
expect(viewport.axisDirection, AxisDirection.down);
await tester.tap(
find.byWidgetPredicate((Widget widget) {
return widget is Radio<AxisDirection> && widget.value == AxisDirection.up;
})
);
await tester.pumpAndSettle();
expect(find.text('AxisDirection.up'), findsOneWidget);
expect(find.text('Axis.vertical'), findsOneWidget);
expect(find.text('GrowthDirection.forward'), findsOneWidget);
expect(find.text('ScrollDirection.idle'), findsOneWidget);
expect(find.byIcon(Icons.arrow_upward_rounded), findsNWidgets(2));
expect(viewport.axisDirection, AxisDirection.up);
});
}
...@@ -30,8 +30,8 @@ import 'theme_data.dart'; ...@@ -30,8 +30,8 @@ import 'theme_data.dart';
/// Input chips work together with other UI elements. They can appear: /// Input chips work together with other UI elements. They can appear:
/// ///
/// * In a [Wrap] widget. /// * In a [Wrap] widget.
/// * In a horizontally scrollable list, like a [ListView] whose /// * In a horizontally scrollable list, for example configured such as a
/// scrollDirection is [Axis.horizontal]. /// [ListView] with [ListView.scrollDirection] set to [Axis.horizontal].
/// ///
/// {@tool dartpad} /// {@tool dartpad}
/// This example shows how to create [InputChip]s with [onSelected] and /// This example shows how to create [InputChip]s with [onSelected] and
......
...@@ -111,7 +111,7 @@ enum RenderComparison { ...@@ -111,7 +111,7 @@ enum RenderComparison {
/// See also: /// See also:
/// ///
/// * [AxisDirection], which is a directional version of this enum (with values /// * [AxisDirection], which is a directional version of this enum (with values
/// light left and right, rather than just horizontal). /// like left and right, rather than just horizontal).
/// * [TextDirection], which disambiguates between left-to-right horizontal /// * [TextDirection], which disambiguates between left-to-right horizontal
/// content and right-to-left horizontal content. /// content and right-to-left horizontal content.
enum Axis { enum Axis {
...@@ -167,33 +167,102 @@ enum VerticalDirection { ...@@ -167,33 +167,102 @@ enum VerticalDirection {
down, down,
} }
/// A direction along either the horizontal or vertical [Axis]. /// A direction along either the horizontal or vertical [Axis] in which the
/// origin, or zero position, is determined.
///
/// This value relates to the direction in which the scroll offset increases
/// from the origin. This value does not represent the direction of user input
/// that may be modifying the scroll offset, such as from a drag. For the
/// active scrolling direction, see [ScrollDirection].
///
/// {@tool dartpad}
/// This sample shows a [CustomScrollView], with [Radio] buttons in the
/// [AppBar.bottom] that change the [AxisDirection] to illustrate different
/// configurations.
///
/// ** See code in examples/api/lib/painting/axis_direction/axis_direction.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [ScrollDirection], the direction of active scrolling, relative to the positive
/// scroll offset axis given by an [AxisDirection] and a [GrowthDirection].
/// * [GrowthDirection], the direction in which slivers and their content are
/// ordered, relative to the scroll offset axis as specified by
/// [AxisDirection].
/// * [CustomScrollView.anchor], the relative position of the zero scroll
/// offset in a viewport and inflection point for [AxisDirection]s of the
/// same cardinal [Axis].
/// * [axisDirectionIsReversed], which returns whether traveling along the
/// given axis direction visits coordinates along that axis in numerically
/// decreasing order.
enum AxisDirection { enum AxisDirection {
/// Zero is at the bottom and positive values are above it: `⇈` /// A direction in the [Axis.vertical] where zero is at the bottom and
/// positive values are above it: `⇈`
/// ///
/// Alphabetical content with a [GrowthDirection.forward] would have the A at /// Alphabetical content with a [GrowthDirection.forward] would have the A at
/// the bottom and the Z at the top. This is an unusual configuration. /// the bottom and the Z at the top.
///
/// For example, the behavior of a [ListView] with [ListView.reverse] set to
/// true would have this axis direction.
///
/// See also:
///
/// * [axisDirectionIsReversed], which returns whether traveling along the
/// given axis direction visits coordinates along that axis in numerically
/// decreasing order.
up, up,
/// Zero is on the left and positive values are to the right of it: `⇉` /// A direction in the [Axis.horizontal] where zero is on the left and
/// positive values are to the right of it: `⇉`
/// ///
/// Alphabetical content with a [GrowthDirection.forward] would have the A on /// Alphabetical content with a [GrowthDirection.forward] would have the A on
/// the left and the Z on the right. This is the ordinary reading order for a /// the left and the Z on the right. This is the ordinary reading order for a
/// horizontal set of tabs in an English application, for example. /// horizontal set of tabs in an English application, for example.
///
/// For example, the behavior of a [ListView] with [ListView.scrollDirection]
/// set to [Axis.horizontal] would have this axis direction.
///
/// See also:
///
/// * [axisDirectionIsReversed], which returns whether traveling along the
/// given axis direction visits coordinates along that axis in numerically
/// decreasing order.
right, right,
/// Zero is at the top and positive values are below it: `⇊` /// A direction in the [Axis.vertical] where zero is at the top and positive
/// values are below it: `⇊`
/// ///
/// Alphabetical content with a [GrowthDirection.forward] would have the A at /// Alphabetical content with a [GrowthDirection.forward] would have the A at
/// the top and the Z at the bottom. This is the ordinary reading order for a /// the top and the Z at the bottom. This is the ordinary reading order for a
/// vertical list. /// vertical list.
///
/// For example, the default behavior of a [ListView] would have this axis
/// direction.
///
/// See also:
///
/// * [axisDirectionIsReversed], which returns whether traveling along the
/// given axis direction visits coordinates along that axis in numerically
/// decreasing order.
down, down,
/// Zero is to the right and positive values are to the left of it: `⇇` /// A direction in the [Axis.horizontal] where zero is to the right and
/// positive values are to the left of it: `⇇`
/// ///
/// Alphabetical content with a [GrowthDirection.forward] would have the A at /// Alphabetical content with a [GrowthDirection.forward] would have the A at
/// the right and the Z at the left. This is the ordinary reading order for a /// the right and the Z at the left. This is the ordinary reading order for a
/// horizontal set of tabs in a Hebrew application, for example. /// horizontal set of tabs in a Hebrew application, for example.
///
/// For example, the behavior of a [ListView] with [ListView.scrollDirection]
/// set to [Axis.horizontal] and [ListView.reverse] set to true would have
/// this axis direction.
///
/// See also:
///
/// * [axisDirectionIsReversed], which returns whether traveling along the
/// given axis direction visits coordinates along that axis in numerically
/// decreasing order.
left, left,
} }
......
...@@ -27,15 +27,48 @@ import 'viewport_offset.dart'; ...@@ -27,15 +27,48 @@ import 'viewport_offset.dart';
/// [GrowthDirection.reverse] would have the Z at the top (at scroll offset /// [GrowthDirection.reverse] would have the Z at the top (at scroll offset
/// zero) and the A below it. /// zero) and the A below it.
/// ///
/// The direction in which the scroll offset increases is given by /// {@template flutter.rendering.GrowthDirection.sample}
/// [applyGrowthDirectionToAxisDirection]. /// Most scroll views by default are ordered [GrowthDirection.forward].
/// Changing the default values of [ScrollView.anchor],
/// [ScrollView.center], or both, can configure a scroll view for
/// [GrowthDirection.reverse].
///
/// {@tool dartpad}
/// This sample shows a [CustomScrollView], with [Radio] buttons in the
/// [AppBar.bottom] that change the [AxisDirection] to illustrate different
/// configurations. The [CustomScrollView.anchor] and [CustomScrollView.center]
/// properties are also set to have the 0 scroll offset positioned in the middle
/// of the viewport, with [GrowthDirection.forward] and [GrowthDirection.reverse]
/// illustrated on either side. The sliver that shares the
/// [CustomScrollView.center] key is positioned at the [CustomScrollView.anchor].
///
/// ** See code in examples/api/lib/rendering/growth_direction/growth_direction.0.dart **
/// {@end-tool}
/// {@endtemplate}
///
/// See also:
///
/// * [applyGrowthDirectionToAxisDirection], which returns the direction in
/// which the scroll offset increases.
enum GrowthDirection { enum GrowthDirection {
/// This sliver's contents are ordered in the same direction as the /// This sliver's contents are ordered in the same direction as the
/// [AxisDirection]. /// [AxisDirection]. For example, a vertical alphabetical list that is going
/// [AxisDirection.down] with a [GrowthDirection.forward] would have the A at
/// the top and the Z at the bottom, with the A adjacent to the origin.
///
/// See also:
///
/// * [applyGrowthDirectionToAxisDirection], which returns the direction in
/// which the scroll offset increases.
forward, forward,
/// This sliver's contents are ordered in the opposite direction of the /// This sliver's contents are ordered in the opposite direction of the
/// [AxisDirection]. /// [AxisDirection].
///
/// See also:
///
/// * [applyGrowthDirectionToAxisDirection], which returns the direction in
/// which the scroll offset increases.
reverse, reverse,
} }
...@@ -57,11 +90,12 @@ AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, G ...@@ -57,11 +90,12 @@ AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, G
} }
} }
/// Flips the [ScrollDirection] if the [GrowthDirection] is [GrowthDirection.reverse]. /// Flips the [ScrollDirection] if the [GrowthDirection] is
/// [GrowthDirection.reverse].
/// ///
/// Specifically, returns `scrollDirection` if `scrollDirection` is /// Specifically, returns `scrollDirection` if `scrollDirection` is
/// [GrowthDirection.forward], otherwise returns [flipScrollDirection] applied to /// [GrowthDirection.forward], otherwise returns [flipScrollDirection] applied
/// `scrollDirection`. /// to `scrollDirection`.
/// ///
/// This function is useful in [RenderSliver] subclasses that are given both an /// This function is useful in [RenderSliver] subclasses that are given both an
/// [ScrollDirection] and a [GrowthDirection] and wish to compute the /// [ScrollDirection] and a [GrowthDirection] and wish to compute the
...@@ -135,6 +169,14 @@ class SliverConstraints extends Constraints { ...@@ -135,6 +169,14 @@ class SliverConstraints extends Constraints {
/// The direction in which the [scrollOffset] and [remainingPaintExtent] /// The direction in which the [scrollOffset] and [remainingPaintExtent]
/// increase. /// increase.
///
/// {@tool dartpad}
/// This sample shows a [CustomScrollView], with [Radio] buttons in the
/// [AppBar.bottom] that change the [AxisDirection] to illustrate different
/// configurations.
///
/// ** See code in examples/api/lib/painting/axis_direction/axis_direction.0.dart **
/// {@end-tool}
final AxisDirection axisDirection; final AxisDirection axisDirection;
/// The direction in which the contents of slivers are ordered, relative to /// The direction in which the contents of slivers are ordered, relative to
...@@ -158,14 +200,16 @@ class SliverConstraints extends Constraints { ...@@ -158,14 +200,16 @@ class SliverConstraints extends Constraints {
/// ///
/// Normally, the absolute zero offset is determined by the viewport's /// Normally, the absolute zero offset is determined by the viewport's
/// [RenderViewport.center] and [RenderViewport.anchor] properties. /// [RenderViewport.center] and [RenderViewport.anchor] properties.
///
/// {@macro flutter.rendering.GrowthDirection.sample}
final GrowthDirection growthDirection; final GrowthDirection growthDirection;
/// The direction in which the user is attempting to scroll, relative to the /// The direction in which the user is attempting to scroll, relative to the
/// [axisDirection] and [growthDirection]. /// [axisDirection] and [growthDirection].
/// ///
/// For example, if [growthDirection] is [GrowthDirection.reverse] and /// For example, if [growthDirection] is [GrowthDirection.forward] and
/// [axisDirection] is [AxisDirection.down], then a /// [axisDirection] is [AxisDirection.down], then a
/// [ScrollDirection.forward] means that the user is scrolling up, in the /// [ScrollDirection.reverse] means that the user is scrolling down, in the
/// positive [scrollOffset] direction. /// positive [scrollOffset] direction.
/// ///
/// If the _user_ is not scrolling, this will return [ScrollDirection.idle] /// If the _user_ is not scrolling, this will return [ScrollDirection.idle]
...@@ -176,6 +220,8 @@ class SliverConstraints extends Constraints { ...@@ -176,6 +220,8 @@ class SliverConstraints extends Constraints {
/// scroll offset. For example, [RenderSliverFloatingPersistentHeader] will /// scroll offset. For example, [RenderSliverFloatingPersistentHeader] will
/// only expand a floating app bar when the [userScrollDirection] is in the /// only expand a floating app bar when the [userScrollDirection] is in the
/// positive scroll offset direction. /// positive scroll offset direction.
///
/// {@macro flutter.rendering.ScrollDirection.sample}
final ScrollDirection userScrollDirection; final ScrollDirection userScrollDirection;
/// The scroll offset, in this sliver's coordinate system, that corresponds to /// The scroll offset, in this sliver's coordinate system, that corresponds to
......
...@@ -1222,9 +1222,10 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix ...@@ -1222,9 +1222,10 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
/// given [offset]. As the offset varies, different children are visible through /// given [offset]. As the offset varies, different children are visible through
/// the viewport. /// the viewport.
/// ///
/// [RenderViewport] hosts a bidirectional list of slivers, anchored on a /// [RenderViewport] hosts a bidirectional list of slivers in a single shared
/// [center] sliver, which is placed at the zero scroll offset. The center /// [Axis], anchored on a [center] sliver, which is placed at the zero scroll
/// widget is displayed in the viewport according to the [anchor] property. /// offset. The center widget is displayed in the viewport according to the
/// [anchor] property.
/// ///
/// Slivers that are earlier in the child list than [center] are displayed in /// Slivers that are earlier in the child list than [center] are displayed in
/// reverse order in the reverse [axisDirection] starting from the [center]. For /// reverse order in the reverse [axisDirection] starting from the [center]. For
...@@ -1234,6 +1235,8 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix ...@@ -1234,6 +1235,8 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
/// example, in the preceding scenario, the first sliver after [center] is /// example, in the preceding scenario, the first sliver after [center] is
/// placed below the [center]. /// placed below the [center].
/// ///
/// {@macro flutter.rendering.GrowthDirection.sample}
///
/// [RenderViewport] cannot contain [RenderBox] children directly. Instead, use /// [RenderViewport] cannot contain [RenderBox] children directly. Instead, use
/// a [RenderSliverList], [RenderSliverFixedExtentList], [RenderSliverGrid], or /// a [RenderSliverList], [RenderSliverFixedExtentList], [RenderSliverGrid], or
/// a [RenderSliverToBoxAdapter], for example. /// a [RenderSliverToBoxAdapter], for example.
...@@ -1323,6 +1326,8 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat ...@@ -1323,6 +1326,8 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
/// vertically centered within the viewport. If the [anchor] is 1.0, and the /// vertically centered within the viewport. If the [anchor] is 1.0, and the
/// [axisDirection] is [AxisDirection.right], then the zero scroll offset is /// [axisDirection] is [AxisDirection.right], then the zero scroll offset is
/// on the left edge of the viewport. /// on the left edge of the viewport.
///
/// {@macro flutter.rendering.GrowthDirection.sample}
double get anchor => _anchor; double get anchor => _anchor;
double _anchor; double _anchor;
set anchor(double value) { set anchor(double value) {
...@@ -1340,10 +1345,15 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat ...@@ -1340,10 +1345,15 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
/// [ViewportOffset.pixels] of [offset] is `0`. /// [ViewportOffset.pixels] of [offset] is `0`.
/// ///
/// Children after [center] will be placed in the [axisDirection] relative to /// Children after [center] will be placed in the [axisDirection] relative to
/// the [center]. Children before [center] will be placed in the opposite of /// the [center].
/// the [axisDirection] relative to the [center]. ///
/// Children before [center] will be placed in the opposite of
/// the [axisDirection] relative to the [center]. These children above
/// [center] will have a growth direction of [GrowthDirection.reverse].
///
/// The [center] must be a direct child of the viewport.
/// ///
/// The [center] must be a child of the viewport. /// {@macro flutter.rendering.GrowthDirection.sample}
RenderSliver? get center => _center; RenderSliver? get center => _center;
RenderSliver? _center; RenderSliver? _center;
set center(RenderSliver? value) { set center(RenderSliver? value) {
......
...@@ -8,28 +8,58 @@ import 'package:flutter/foundation.dart'; ...@@ -8,28 +8,58 @@ import 'package:flutter/foundation.dart';
/// The direction of a scroll, relative to the positive scroll offset axis given /// The direction of a scroll, relative to the positive scroll offset axis given
/// by an [AxisDirection] and a [GrowthDirection]. /// by an [AxisDirection] and a [GrowthDirection].
/// ///
/// This contrasts to [GrowthDirection] in that it has a third value, [idle], /// This is similar to [GrowthDirection], but contrasts in that it has a third
/// for the case where no scroll is occurring. /// value, [idle], for the case where no scroll is occurring.
/// ///
/// This is used by [RenderSliverFloatingPersistentHeader] to only expand when /// This is used by [RenderSliverFloatingPersistentHeader] to only expand when
/// the user is scrolling in the same direction as the detected scroll offset /// the user is scrolling in the same direction as the detected scroll offset
/// change. /// change.
///
/// {@template flutter.rendering.ScrollDirection.sample}
/// {@tool dartpad}
/// This sample shows a [CustomScrollView], with [Radio] buttons in the
/// [AppBar.bottom] that change the [AxisDirection] to illustrate different
/// configurations. With a [NotificationListener] to listen to
/// [UserScrollNotification]s, which occur when the [ScrollDirection] changes
/// or stops.
///
/// ** See code in examples/api/lib/rendering/scroll_direction/scroll_direction.0.dart **
/// {@end-tool}
/// {@endtemplate}
///
/// See also:
///
/// * [AxisDirection], which is a directional version of this enum (with values
/// like left and right, rather than just horizontal).
/// * [GrowthDirection], the direction in which slivers and their content are
/// ordered, relative to the scroll offset axis as specified by
/// [AxisDirection].
/// * [UserScrollNotification], which will notify listeners when the
/// [ScrollDirection] changes.
enum ScrollDirection { enum ScrollDirection {
/// No scrolling is underway. /// No scrolling is underway.
idle, idle,
/// Scrolling is happening in the positive scroll offset direction. /// Scrolling is happening in the negative scroll offset direction.
/// ///
/// For example, for the [GrowthDirection.forward] part of a vertical /// For example, for the [GrowthDirection.forward] part of a vertical
/// [AxisDirection.down] list, this means the content is moving up, exposing /// [AxisDirection.down] list, which is the default directional configuration
/// lower content. /// of all scroll views, this means the content is going down, exposing
/// earlier content as it approaches the zero position.
///
/// An anecdote for this most common case is 'forward is toward' the zero
/// position.
forward, forward,
/// Scrolling is happening in the negative scroll offset direction. /// Scrolling is happening in the positive scroll offset direction.
/// ///
/// For example, for the [GrowthDirection.forward] part of a vertical /// For example, for the [GrowthDirection.forward] part of a vertical
/// [AxisDirection.down] list, this means the content is moving down, exposing /// [AxisDirection.down] list, which is the default directional configuration
/// earlier content. /// of all scroll views, this means the content is moving up, exposing
/// lower content.
///
/// An anecdote for this most common case is reversing, or backing away, from
/// the zero position.
reverse, reverse,
} }
...@@ -216,6 +246,8 @@ abstract class ViewportOffset extends ChangeNotifier { ...@@ -216,6 +246,8 @@ abstract class ViewportOffset extends ChangeNotifier {
/// For example, [RenderSliverFloatingPersistentHeader] will only expand a /// For example, [RenderSliverFloatingPersistentHeader] will only expand a
/// floating app bar when the [userScrollDirection] is in the positive scroll /// floating app bar when the [userScrollDirection] is in the positive scroll
/// offset direction. /// offset direction.
///
/// {@macro flutter.rendering.ScrollDirection.sample}
ScrollDirection get userScrollDirection; ScrollDirection get userScrollDirection;
/// Whether a viewport is allowed to change [pixels] implicitly to respond to /// Whether a viewport is allowed to change [pixels] implicitly to respond to
......
...@@ -401,9 +401,7 @@ abstract class _AnimatedScrollView extends StatefulWidget { ...@@ -401,9 +401,7 @@ abstract class _AnimatedScrollView extends StatefulWidget {
/// {@endtemplate} /// {@endtemplate}
final int initialItemCount; final int initialItemCount;
/// The axis along which the scroll view scrolls. /// {@macro flutter.widgets.scroll_view.scrollDirection}
///
/// Defaults to [Axis.vertical].
final Axis scrollDirection; final Axis scrollDirection;
/// Whether the scroll view scrolls in the reading direction. /// Whether the scroll view scrolls in the reading direction.
......
...@@ -196,9 +196,7 @@ class NestedScrollView extends StatefulWidget { ...@@ -196,9 +196,7 @@ class NestedScrollView extends StatefulWidget {
/// scroll view is scrolled. /// scroll view is scrolled.
final ScrollController? controller; final ScrollController? controller;
/// The axis along which the scroll view scrolls. /// {@macro flutter.widgets.scroll_view.scrollDirection}
///
/// Defaults to [Axis.vertical].
final Axis scrollDirection; final Axis scrollDirection;
/// Whether the scroll view scrolls in the reading direction. /// Whether the scroll view scrolls in the reading direction.
......
...@@ -823,7 +823,10 @@ class PageView extends StatefulWidget { ...@@ -823,7 +823,10 @@ class PageView extends StatefulWidget {
/// {@macro flutter.widgets.scrollable.restorationId} /// {@macro flutter.widgets.scrollable.restorationId}
final String? restorationId; final String? restorationId;
/// The axis along which the page view scrolls. /// The [Axis] along which the scroll view's offset increases with each page.
///
/// For the direction in which active scrolling may be occurring, see
/// [ScrollDirection].
/// ///
/// Defaults to [Axis.horizontal]. /// Defaults to [Axis.horizontal].
final Axis scrollDirection; final Axis scrollDirection;
......
...@@ -84,6 +84,9 @@ class PrimaryScrollController extends InheritedWidget { ...@@ -84,6 +84,9 @@ class PrimaryScrollController extends InheritedWidget {
/// PrimaryScrollController.none into the tree to prevent further descendant /// PrimaryScrollController.none into the tree to prevent further descendant
/// ScrollViews from inheriting the current PrimaryScrollController. /// ScrollViews from inheriting the current PrimaryScrollController.
/// ///
/// For the direction in which active scrolling may be occurring, see
/// [ScrollDirection].
///
/// Defaults to [Axis.vertical]. /// Defaults to [Axis.vertical].
final Axis? scrollDirection; final Axis? scrollDirection;
......
...@@ -268,8 +268,13 @@ class ScrollEndNotification extends ScrollNotification { ...@@ -268,8 +268,13 @@ class ScrollEndNotification extends ScrollNotification {
} }
} }
/// A notification that the user has changed the direction in which they are /// A notification that the user has changed the [ScrollDirection] in which they
/// scrolling. /// are scrolling, or have stopped scrolling.
///
/// For the direction that the [ScrollView] is oriented to, and the direction
/// contents are being laid out in, see [AxisDirection] & [GrowthDirection].
///
/// {@macro flutter.rendering.ScrollDirection.sample}
/// ///
/// See also: /// See also:
/// ///
...@@ -284,6 +289,13 @@ class UserScrollNotification extends ScrollNotification { ...@@ -284,6 +289,13 @@ class UserScrollNotification extends ScrollNotification {
}); });
/// The direction in which the user is scrolling. /// The direction in which the user is scrolling.
///
/// This does not represent the current [AxisDirection] or [GrowthDirection]
/// of the [Viewport], which respectively represent the direction that the
/// scroll offset is increasing in, and the direction that contents are being
/// laid out in.
///
/// {@macro flutter.rendering.ScrollDirection.sample}
final ScrollDirection direction; final ScrollDirection direction;
@override @override
......
...@@ -114,7 +114,10 @@ abstract class ScrollView extends StatelessWidget { ...@@ -114,7 +114,10 @@ abstract class ScrollView extends StatelessWidget {
physics = physics ?? ((primary ?? false) || (primary == null && controller == null && identical(scrollDirection, Axis.vertical)) ? const AlwaysScrollableScrollPhysics() : null); physics = physics ?? ((primary ?? false) || (primary == null && controller == null && identical(scrollDirection, Axis.vertical)) ? const AlwaysScrollableScrollPhysics() : null);
/// {@template flutter.widgets.scroll_view.scrollDirection} /// {@template flutter.widgets.scroll_view.scrollDirection}
/// The axis along which the scroll view scrolls. /// The [Axis] along which the scroll view's offset increases.
///
/// For the direction in which active scrolling may be occurring, see
/// [ScrollDirection].
/// ///
/// Defaults to [Axis.vertical]. /// Defaults to [Axis.vertical].
/// {@endtemplate} /// {@endtemplate}
...@@ -276,6 +279,23 @@ abstract class ScrollView extends StatelessWidget { ...@@ -276,6 +279,23 @@ abstract class ScrollView extends StatelessWidget {
/// supports [center]; for that class, the given key must be the key of one of /// supports [center]; for that class, the given key must be the key of one of
/// the slivers in the [CustomScrollView.slivers] list. /// the slivers in the [CustomScrollView.slivers] list.
/// ///
/// Most scroll views by default are ordered [GrowthDirection.forward].
/// Changing the default values of [ScrollView.anchor],
/// [ScrollView.center], or both, can configure a scroll view for
/// [GrowthDirection.reverse].
///
/// {@tool dartpad}
/// This sample shows a [CustomScrollView], with [Radio] buttons in the
/// [AppBar.bottom] that change the [AxisDirection] to illustrate different
/// configurations. The [CustomScrollView.anchor] and [CustomScrollView.center]
/// properties are also set to have the 0 scroll offset positioned in the middle
/// of the viewport, with [GrowthDirection.forward] and [GrowthDirection.reverse]
/// illustrated on either side. The sliver that shares the
/// [CustomScrollView.center] key is positioned at the [CustomScrollView.anchor].
///
/// ** See code in examples/api/lib/rendering/growth_direction/growth_direction.0.dart **
/// {@end-tool}
///
/// See also: /// See also:
/// ///
/// * [anchor], which controls where the [center] as aligned in the viewport. /// * [anchor], which controls where the [center] as aligned in the viewport.
...@@ -290,6 +310,23 @@ abstract class ScrollView extends StatelessWidget { ...@@ -290,6 +310,23 @@ abstract class ScrollView extends StatelessWidget {
/// within the viewport. If the [anchor] is 1.0, and the axis direction is /// within the viewport. If the [anchor] is 1.0, and the axis direction is
/// [AxisDirection.right], then the zero scroll offset is on the left edge of /// [AxisDirection.right], then the zero scroll offset is on the left edge of
/// the viewport. /// the viewport.
///
/// Most scroll views by default are ordered [GrowthDirection.forward].
/// Changing the default values of [ScrollView.anchor],
/// [ScrollView.center], or both, can configure a scroll view for
/// [GrowthDirection.reverse].
///
/// {@tool dartpad}
/// This sample shows a [CustomScrollView], with [Radio] buttons in the
/// [AppBar.bottom] that change the [AxisDirection] to illustrate different
/// configurations. The [CustomScrollView.anchor] and [CustomScrollView.center]
/// properties are also set to have the 0 scroll offset positioned in the middle
/// of the viewport, with [GrowthDirection.forward] and [GrowthDirection.reverse]
/// illustrated on either side. The sliver that shares the
/// [CustomScrollView.center] key is positioned at the [CustomScrollView.anchor].
///
/// ** See code in examples/api/lib/rendering/growth_direction/growth_direction.0.dart **
/// {@end-tool}
/// {@endtemplate} /// {@endtemplate}
final double anchor; final double anchor;
......
...@@ -1087,9 +1087,9 @@ class RawScrollbar extends StatefulWidget { ...@@ -1087,9 +1087,9 @@ class RawScrollbar extends StatefulWidget {
/// * When providing a controller, the same ScrollController must also be /// * When providing a controller, the same ScrollController must also be
/// provided to the associated Scrollable widget. /// provided to the associated Scrollable widget.
/// * The [PrimaryScrollController] is used by default for a [ScrollView] /// * The [PrimaryScrollController] is used by default for a [ScrollView]
/// that has not been provided a [ScrollController] and that has an /// that has not been provided a [ScrollController] and that has a
/// [Axis.vertical] [ScrollDirection]. This automatic behavior does not /// [ScrollView.scrollDirection] of [Axis.vertical]. This automatic
/// apply to those with a ScrollDirection of Axis.horizontal. To explicitly /// behavior does not apply to those with [Axis.horizontal]. To explicitly
/// use the PrimaryScrollController, set [ScrollView.primary] to true. /// use the PrimaryScrollController, set [ScrollView.primary] to true.
/// ///
/// Defaults to false when null. /// Defaults to false when null.
...@@ -1172,9 +1172,9 @@ class RawScrollbar extends StatefulWidget { ...@@ -1172,9 +1172,9 @@ class RawScrollbar extends StatefulWidget {
/// * When providing a controller, the same ScrollController must also be /// * When providing a controller, the same ScrollController must also be
/// provided to the associated Scrollable widget. /// provided to the associated Scrollable widget.
/// * The [PrimaryScrollController] is used by default for a [ScrollView] /// * The [PrimaryScrollController] is used by default for a [ScrollView]
/// that has not been provided a [ScrollController] and that has an /// that has not been provided a [ScrollController] and that has a
/// [Axis.vertical] [ScrollDirection]. This automatic behavior does not /// [ScrollView.scrollDirection] of [Axis.vertical]. This automatic
/// apply to those with a ScrollDirection of Axis.horizontal. To explicitly /// behavior does not apply to those with Axis.horizontal. To explicitly
/// use the PrimaryScrollController, set [ScrollView.primary] to true. /// use the PrimaryScrollController, set [ScrollView.primary] to true.
/// ///
/// Defaults to false when null. /// Defaults to false when null.
...@@ -1576,7 +1576,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -1576,7 +1576,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
'ScrollController should be associated with the ScrollView that ' 'ScrollController should be associated with the ScrollView that '
'the Scrollbar is being applied to.' 'the Scrollbar is being applied to.'
'${tryPrimary '${tryPrimary
? 'A ScrollView with an Axis.vertical ScrollDirection on mobile ' ? 'When ScrollView.scrollDirection is Axis.vertical on mobile '
'platforms will automatically use the ' 'platforms will automatically use the '
'PrimaryScrollController if the user has not provided a ' 'PrimaryScrollController if the user has not provided a '
'ScrollController. To use the PrimaryScrollController ' 'ScrollController. To use the PrimaryScrollController '
......
...@@ -158,9 +158,7 @@ class SingleChildScrollView extends StatelessWidget { ...@@ -158,9 +158,7 @@ class SingleChildScrollView extends StatelessWidget {
'true and pass an explicit controller.', 'true and pass an explicit controller.',
); );
/// The axis along which the scroll view scrolls. /// {@macro flutter.widgets.scroll_view.scrollDirection}
///
/// Defaults to [Axis.vertical].
final Axis scrollDirection; final Axis scrollDirection;
/// Whether the scroll view scrolls in the reading direction. /// Whether the scroll view scrolls in the reading direction.
......
...@@ -96,6 +96,8 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -96,6 +96,8 @@ class Viewport extends MultiChildRenderObjectWidget {
/// vertically centered within the viewport. If the [anchor] is 1.0, and the /// vertically centered within the viewport. If the [anchor] is 1.0, and the
/// [axisDirection] is [AxisDirection.right], then the zero scroll offset is /// [axisDirection] is [AxisDirection.right], then the zero scroll offset is
/// on the left edge of the viewport. /// on the left edge of the viewport.
///
/// {@macro flutter.rendering.GrowthDirection.sample}
final double anchor; final double anchor;
/// Which part of the content inside the viewport should be visible. /// Which part of the content inside the viewport should be visible.
...@@ -115,6 +117,8 @@ class Viewport extends MultiChildRenderObjectWidget { ...@@ -115,6 +117,8 @@ class Viewport extends MultiChildRenderObjectWidget {
/// the [axisDirection] relative to the [center]. /// the [axisDirection] relative to the [center].
/// ///
/// The [center] must be the key of a child of the viewport. /// The [center] must be the key of a child of the viewport.
///
/// {@macro flutter.rendering.GrowthDirection.sample}
final Key? center; final Key? center;
/// {@macro flutter.rendering.RenderViewportBase.cacheExtent} /// {@macro flutter.rendering.RenderViewportBase.cacheExtent}
......
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