mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Add maybeOf
for all the cases where of
returns nullable. (#114120)
This commit is contained in:
parent
b20b7d995b
commit
37b72342b0
@ -210,8 +210,8 @@ class _ExpansionPanelsDemoState extends State<ExpansionPanelsDemo> {
|
||||
builder: (BuildContext context) {
|
||||
return CollapsibleBody(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
onSave: () { Form.of(context)!.save(); close(); },
|
||||
onCancel: () { Form.of(context)!.reset(); close(); },
|
||||
onSave: () { Form.of(context).save(); close(); },
|
||||
onCancel: () { Form.of(context).reset(); close(); },
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: TextFormField(
|
||||
@ -244,8 +244,8 @@ class _ExpansionPanelsDemoState extends State<ExpansionPanelsDemo> {
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return CollapsibleBody(
|
||||
onSave: () { Form.of(context)!.save(); close(); },
|
||||
onCancel: () { Form.of(context)!.reset(); close(); },
|
||||
onSave: () { Form.of(context).save(); close(); },
|
||||
onCancel: () { Form.of(context).reset(); close(); },
|
||||
child: FormField<Location>(
|
||||
initialValue: item.value,
|
||||
onSaved: (Location? result) { item.value = result; },
|
||||
@ -298,8 +298,8 @@ class _ExpansionPanelsDemoState extends State<ExpansionPanelsDemo> {
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return CollapsibleBody(
|
||||
onSave: () { Form.of(context)!.save(); close(); },
|
||||
onCancel: () { Form.of(context)!.reset(); close(); },
|
||||
onSave: () { Form.of(context).save(); close(); },
|
||||
onCancel: () { Form.of(context).reset(); close(); },
|
||||
child: FormField<double>(
|
||||
initialValue: item.value,
|
||||
onSaved: (double? value) { item.value = value; },
|
||||
|
@ -12,7 +12,7 @@ class _PageSelector extends StatelessWidget {
|
||||
final List<Icon>? icons;
|
||||
|
||||
void _handleArrowButtonPress(BuildContext context, int delta) {
|
||||
final TabController controller = DefaultTabController.of(context)!;
|
||||
final TabController controller = DefaultTabController.of(context);
|
||||
if (!controller.indexIsChanging) {
|
||||
controller.animateTo((controller.index + delta).clamp(0, icons!.length - 1));
|
||||
}
|
||||
@ -20,7 +20,7 @@ class _PageSelector extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TabController? controller = DefaultTabController.of(context);
|
||||
final TabController? controller = DefaultTabController.maybeOf(context);
|
||||
final Color color = Theme.of(context).colorScheme.secondary;
|
||||
return SafeArea(
|
||||
top: false,
|
||||
|
@ -63,7 +63,7 @@ class TabbedComponentDemoScaffold extends StatefulWidget {
|
||||
|
||||
class _TabbedComponentDemoScaffoldState extends State<TabbedComponentDemoScaffold> {
|
||||
void _showExampleCode(BuildContext context) {
|
||||
final String? tag = widget.demos![DefaultTabController.of(context)!.index].exampleCodeTag;
|
||||
final String? tag = widget.demos![DefaultTabController.of(context).index].exampleCodeTag;
|
||||
if (tag != null) {
|
||||
Navigator.push(context, MaterialPageRoute<FullScreenCodeDialog>(
|
||||
builder: (BuildContext context) => FullScreenCodeDialog(exampleCodeTag: tag)
|
||||
@ -72,7 +72,7 @@ class _TabbedComponentDemoScaffoldState extends State<TabbedComponentDemoScaffol
|
||||
}
|
||||
|
||||
Future<void> _showApiDocumentation(BuildContext context) async {
|
||||
final String? url = widget.demos![DefaultTabController.of(context)!.index].documentationUrl;
|
||||
final String? url = widget.demos![DefaultTabController.of(context).index].documentationUrl;
|
||||
if (url == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateM
|
||||
return FloatingActionButton(
|
||||
child: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
_play(_allDemos[DefaultTabController.of(context)!.index]);
|
||||
_play(_allDemos[DefaultTabController.of(context).index]);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
@ -172,8 +172,8 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
|
||||
markers[MarkerType.topLeft] = box!.localToGlobal(Offset.zero);
|
||||
final Size size = box.size;
|
||||
markers[MarkerType.bottomRight] = box.localToGlobal(Offset(size.width, size.height));
|
||||
final ScrollableState? scrollable = Scrollable.of(target.currentContext!);
|
||||
markersScrollOffset = scrollable!.position.pixels;
|
||||
final ScrollableState scrollable = Scrollable.of(target.currentContext!);
|
||||
markersScrollOffset = scrollable.position.pixels;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ class FromSectionExample extends StatelessWidget {
|
||||
child: Form(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
onChanged: () {
|
||||
Form.of(primaryFocus!.context!)?.save();
|
||||
Form.maybeOf(primaryFocus!.context!)?.save();
|
||||
},
|
||||
child: CupertinoFormSection.insetGrouped(
|
||||
header: const Text('SECTION 1'),
|
||||
|
@ -38,7 +38,7 @@ class MyStatelessWidget extends StatelessWidget {
|
||||
// The Builder widget is used to have a different BuildContext to access
|
||||
// closest DefaultTabController.
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
final TabController tabController = DefaultTabController.of(context)!;
|
||||
final TabController tabController = DefaultTabController.of(context);
|
||||
tabController.addListener(() {
|
||||
if (!tabController.indexIsChanging) {
|
||||
// Your code goes here.
|
||||
|
@ -44,7 +44,7 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
|
||||
child: Form(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
onChanged: () {
|
||||
Form.of(primaryFocus!.context!)!.save();
|
||||
Form.of(primaryFocus!.context!).save();
|
||||
},
|
||||
child: Wrap(
|
||||
children: List<Widget>.generate(5, (int index) {
|
||||
|
@ -90,7 +90,7 @@ class CupertinoPageScaffold extends StatefulWidget {
|
||||
class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
|
||||
|
||||
void _handleStatusBarTap() {
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.of(context);
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.maybeOf(context);
|
||||
// Only act on the scroll controller if it has any attached scroll positions.
|
||||
if (primaryScrollController != null && primaryScrollController.hasClients) {
|
||||
primaryScrollController.animateTo(
|
||||
|
@ -602,7 +602,7 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||
}
|
||||
final String packageName = data.packages[widget.selectedId.value ?? 0];
|
||||
final List<int> bindings = data.packageLicenseBindings[packageName]!;
|
||||
_MasterDetailFlow.of(context)!.setInitialDetailPage(
|
||||
_MasterDetailFlow.of(context).setInitialDetailPage(
|
||||
_DetailArguments(
|
||||
packageName,
|
||||
bindings.map((int i) => data.licenses[i]).toList(growable: false),
|
||||
@ -632,7 +632,7 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||
numberLicenses: bindings.length,
|
||||
onTap: () {
|
||||
widget.selectedId.value = packageIndex;
|
||||
_MasterDetailFlow.of(context)!.openDetailPage(_DetailArguments(
|
||||
_MasterDetailFlow.of(context).openDetailPage(_DetailArguments(
|
||||
packageName,
|
||||
bindings.map((int i) => data.licenses[i]).toList(growable: false),
|
||||
));
|
||||
@ -1073,7 +1073,7 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||
// ```dart
|
||||
// _MasterDetailFlow.of(context).openDetailPage(arguments);
|
||||
// ```
|
||||
static _MasterDetailFlowProxy? of(BuildContext context) {
|
||||
static _MasterDetailFlowProxy of(BuildContext context) {
|
||||
_PageOpener? pageOpener = context.findAncestorStateOfType<_MasterDetailScaffoldState>();
|
||||
pageOpener ??= context.findAncestorStateOfType<_MasterDetailFlowState>();
|
||||
assert(() {
|
||||
@ -1086,7 +1086,7 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return pageOpener != null ? _MasterDetailFlowProxy._(pageOpener) : null;
|
||||
return _MasterDetailFlowProxy._(pageOpener!);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1339,13 +1339,13 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||
@override
|
||||
void openDetailPage(Object arguments) {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) => _detailArguments.value = arguments);
|
||||
_MasterDetailFlow.of(context)!.openDetailPage(arguments);
|
||||
_MasterDetailFlow.of(context).openDetailPage(arguments);
|
||||
}
|
||||
|
||||
@override
|
||||
void setInitialDetailPage(Object arguments) {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) => _detailArguments.value = arguments);
|
||||
_MasterDetailFlow.of(context)!.setInitialDetailPage(arguments);
|
||||
_MasterDetailFlow.of(context).setInitialDetailPage(arguments);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -820,13 +820,9 @@ class _AppBarState extends State<AppBar> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
if (_scrollNotificationObserver != null) {
|
||||
_scrollNotificationObserver!.removeListener(_handleScrollNotification);
|
||||
}
|
||||
_scrollNotificationObserver = ScrollNotificationObserver.of(context);
|
||||
if (_scrollNotificationObserver != null) {
|
||||
_scrollNotificationObserver!.addListener(_handleScrollNotification);
|
||||
}
|
||||
_scrollNotificationObserver?.removeListener(_handleScrollNotification);
|
||||
_scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context);
|
||||
_scrollNotificationObserver?.addListener(_handleScrollNotification);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -806,7 +806,7 @@ class _FocusedDate extends InheritedWidget {
|
||||
return !DateUtils.isSameDay(date, oldWidget.date);
|
||||
}
|
||||
|
||||
static DateTime? of(BuildContext context) {
|
||||
static DateTime? maybeOf(BuildContext context) {
|
||||
final _FocusedDate? focusedDate = context.dependOnInheritedWidgetOfExactType<_FocusedDate>();
|
||||
return focusedDate?.date;
|
||||
}
|
||||
@ -887,7 +887,7 @@ class _DayPickerState extends State<_DayPicker> {
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
// Check to see if the focused date is in this month, if so focus it.
|
||||
final DateTime? focusedDate = _FocusedDate.of(context);
|
||||
final DateTime? focusedDate = _FocusedDate.maybeOf(context);
|
||||
if (focusedDate != null && DateUtils.isSameMonth(widget.displayedMonth, focusedDate)) {
|
||||
_dayFocusNodes[focusedDate.day - 1].requestFocus();
|
||||
}
|
||||
|
@ -1940,12 +1940,11 @@ class _FocusedDate extends InheritedWidget {
|
||||
return !DateUtils.isSameDay(date, oldWidget.date) || scrollDirection != oldWidget.scrollDirection;
|
||||
}
|
||||
|
||||
static _FocusedDate? of(BuildContext context) {
|
||||
static _FocusedDate? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<_FocusedDate>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _DayHeaders extends StatelessWidget {
|
||||
const _DayHeaders();
|
||||
|
||||
@ -2217,7 +2216,7 @@ class _MonthItemState extends State<_MonthItem> {
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
// Check to see if the focused date is in this month, if so focus it.
|
||||
final DateTime? focusedDate = _FocusedDate.of(context)?.date;
|
||||
final DateTime? focusedDate = _FocusedDate.maybeOf(context)?.date;
|
||||
if (focusedDate != null && DateUtils.isSameMonth(widget.displayedMonth, focusedDate)) {
|
||||
_dayFocusNodes[focusedDate.day - 1].requestFocus();
|
||||
}
|
||||
@ -2237,7 +2236,7 @@ class _MonthItemState extends State<_MonthItem> {
|
||||
|
||||
void _dayFocusChanged(bool focused) {
|
||||
if (focused) {
|
||||
final TraversalDirection? focusDirection = _FocusedDate.of(context)?.scrollDirection;
|
||||
final TraversalDirection? focusDirection = _FocusedDate.maybeOf(context)?.scrollDirection;
|
||||
if (focusDirection != null) {
|
||||
ScrollPositionAlignmentPolicy policy = ScrollPositionAlignmentPolicy.explicit;
|
||||
switch (focusDirection) {
|
||||
|
@ -332,7 +332,7 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
|
||||
_iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
|
||||
_backgroundColor = _controller.drive(_backgroundColorTween.chain(_easeOutTween));
|
||||
|
||||
_isExpanded = PageStorage.of(context)?.readState(context) as bool? ?? widget.initiallyExpanded;
|
||||
_isExpanded = PageStorage.maybeOf(context)?.readState(context) as bool? ?? widget.initiallyExpanded;
|
||||
if (_isExpanded) {
|
||||
_controller.value = 1.0;
|
||||
}
|
||||
@ -359,7 +359,7 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
|
||||
});
|
||||
});
|
||||
}
|
||||
PageStorage.of(context)?.writeState(context, _isExpanded);
|
||||
PageStorage.maybeOf(context)?.writeState(context, _isExpanded);
|
||||
});
|
||||
widget.onExpansionChanged?.call(_isExpanded);
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ class _InkState extends State<Ink> {
|
||||
_ink = InkDecoration(
|
||||
decoration: widget.decoration,
|
||||
configuration: createLocalImageConfiguration(context),
|
||||
controller: Material.of(context)!,
|
||||
controller: Material.of(context),
|
||||
referenceBox: _boxKey.currentContext!.findRenderObject()! as RenderBox,
|
||||
onRemoved: _handleRemoved,
|
||||
);
|
||||
|
@ -197,7 +197,7 @@ class _ParentInkResponseProvider extends InheritedWidget {
|
||||
@override
|
||||
bool updateShouldNotify(_ParentInkResponseProvider oldWidget) => state != oldWidget.state;
|
||||
|
||||
static _ParentInkResponseState? of(BuildContext context) {
|
||||
static _ParentInkResponseState? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<_ParentInkResponseProvider>()?.state;
|
||||
}
|
||||
}
|
||||
@ -600,7 +600,7 @@ class InkResponse extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _ParentInkResponseState? parentState = _ParentInkResponseProvider.of(context);
|
||||
final _ParentInkResponseState? parentState = _ParentInkResponseProvider.maybeOf(context);
|
||||
return _InkResponseStateWidget(
|
||||
onTap: onTap,
|
||||
onTapDown: onTapDown,
|
||||
@ -916,7 +916,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
}
|
||||
final RenderBox referenceBox = context.findRenderObject()! as RenderBox;
|
||||
_highlights[type] = InkHighlight(
|
||||
controller: Material.of(context)!,
|
||||
controller: Material.of(context),
|
||||
referenceBox: referenceBox,
|
||||
color: resolvedOverlayColor,
|
||||
shape: widget.highlightShape,
|
||||
@ -952,7 +952,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
}
|
||||
|
||||
InteractiveInkFeature _createInkFeature(Offset globalPosition) {
|
||||
final MaterialInkController inkController = Material.of(context)!;
|
||||
final MaterialInkController inkController = Material.of(context);
|
||||
final RenderBox referenceBox = context.findRenderObject()! as RenderBox;
|
||||
final Offset position = referenceBox.globalToLocal(globalPosition);
|
||||
final Color color = widget.overlayColor?.resolve(statesController.value) ?? widget.splashColor ?? Theme.of(context).splashColor;
|
||||
|
@ -348,14 +348,55 @@ class Material extends StatefulWidget {
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// MaterialInkController? inkController = Material.of(context);
|
||||
/// MaterialInkController? inkController = Material.maybeOf(context);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be expensive (it walks the element tree).
|
||||
static MaterialInkController? of(BuildContext context) {
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Material.of], which is similar to this method, but asserts if
|
||||
/// no [Material] ancestor is found.
|
||||
static MaterialInkController? maybeOf(BuildContext context) {
|
||||
return context.findAncestorRenderObjectOfType<_RenderInkFeatures>();
|
||||
}
|
||||
|
||||
/// The ink controller from the closest instance of [Material] that encloses
|
||||
/// the given context.
|
||||
///
|
||||
/// If no [Material] widget ancestor can be found then this method will assert
|
||||
/// in debug mode, and throw an exception in release mode.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// MaterialInkController inkController = Material.of(context);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be expensive (it walks the element tree).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Material.maybeOf], which is similar to this method, but returns null if
|
||||
/// no [Material] ancestor is found.
|
||||
static MaterialInkController of(BuildContext context) {
|
||||
final MaterialInkController? controller = maybeOf(context);
|
||||
assert(() {
|
||||
if (controller == null) {
|
||||
throw FlutterError(
|
||||
'Material.of() was called with a context that does not contain a Material widget.\n'
|
||||
'No Material widget ancestor could be found starting from the context that was passed to '
|
||||
'Material.of(). This can happen because you are using a widget that looks for a Material '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return controller!;
|
||||
}
|
||||
|
||||
@override
|
||||
State<Material> createState() => _MaterialState();
|
||||
|
||||
|
@ -305,7 +305,7 @@ class _MenuAnchorState extends State<MenuAnchor> {
|
||||
_parent = _MenuAnchorState._maybeOf(context);
|
||||
_parent?._addChild(this);
|
||||
_position?.isScrollingNotifier.removeListener(_handleScroll);
|
||||
_position = Scrollable.of(context)?.position;
|
||||
_position = Scrollable.maybeOf(context)?.position;
|
||||
_position?.isScrollingNotifier.addListener(_handleScroll);
|
||||
final Size newSize = MediaQuery.of(context).size;
|
||||
if (_viewSize != null && newSize != _viewSize) {
|
||||
|
@ -267,7 +267,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_firstRowIndex = PageStorage.of(context)?.readState(context) as int? ?? widget.initialFirstRowIndex ?? 0;
|
||||
_firstRowIndex = PageStorage.maybeOf(context)?.readState(context) as int? ?? widget.initialFirstRowIndex ?? 0;
|
||||
widget.source.addListener(_handleDataSourceChanged);
|
||||
_handleDataSourceChanged();
|
||||
}
|
||||
|
@ -2536,7 +2536,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
|
||||
// top. We implement this by looking up the primary scroll controller and
|
||||
// scrolling it to the top when tapped.
|
||||
void _handleStatusBarTap() {
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.of(context);
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.maybeOf(context);
|
||||
if (primaryScrollController != null && primaryScrollController.hasClients) {
|
||||
primaryScrollController.animateTo(
|
||||
0.0,
|
||||
|
@ -375,18 +375,65 @@ class DefaultTabController extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.ProxyWidget.child}
|
||||
final Widget child;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
/// The closest instance of [DefaultTabController] that encloses the given
|
||||
/// context, or null if none is found.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// Typical usage is as follows:
|
||||
/// {@tool snippet} Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// TabController controller = DefaultTabController.of(context)!;
|
||||
/// TabController? controller = DefaultTabController.maybeOf(context);
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
static TabController? of(BuildContext context) {
|
||||
final _TabControllerScope? scope = context.dependOnInheritedWidgetOfExactType<_TabControllerScope>();
|
||||
return scope?.controller;
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [DefaultTabController] in the [context], if there is one.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [DefaultTabController.of], which is similar to this method, but asserts
|
||||
/// if no [DefaultTabController] ancestor is found.
|
||||
static TabController? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<_TabControllerScope>()?.controller;
|
||||
}
|
||||
|
||||
/// The closest instance of [DefaultTabController] that encloses the given
|
||||
/// context.
|
||||
///
|
||||
/// If no instance is found, this method will assert in debug mode and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [DefaultTabController] in the [context].
|
||||
///
|
||||
/// {@tool snippet} Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// TabController controller = DefaultTabController.of(context);
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [DefaultTabController.maybeOf], which is similar to this method, but
|
||||
/// returns null if no [DefaultTabController] ancestor is found.
|
||||
static TabController of(BuildContext context) {
|
||||
final TabController? controller = maybeOf(context);
|
||||
assert(() {
|
||||
if (controller == null) {
|
||||
throw FlutterError(
|
||||
'DefaultTabController.of() was called with a context that does not '
|
||||
'contain a DefaultTabController widget.\n'
|
||||
'No DefaultTabController widget ancestor could be found starting from '
|
||||
'the context that was passed to DefaultTabController.of(). This can '
|
||||
'happen because you are using a widget that looks for a DefaultTabController '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return controller!;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -954,7 +954,7 @@ class _TabBarState extends State<TabBar> {
|
||||
// TODO(xu-baolin): Remove automatic adjustment to white color indicator
|
||||
// with a better long-term solution.
|
||||
// https://github.com/flutter/flutter/pull/68171#pullrequestreview-517753917
|
||||
if (widget.automaticIndicatorColorAdjustment && color.value == Material.of(context)?.color?.value) {
|
||||
if (widget.automaticIndicatorColorAdjustment && color.value == Material.maybeOf(context)?.color?.value) {
|
||||
color = Colors.white;
|
||||
}
|
||||
|
||||
@ -972,7 +972,7 @@ class _TabBarState extends State<TabBar> {
|
||||
bool get _controllerIsValid => _controller?.animation != null;
|
||||
|
||||
void _updateTabController() {
|
||||
final TabController? newController = widget.controller ?? DefaultTabController.of(context);
|
||||
final TabController? newController = widget.controller ?? DefaultTabController.maybeOf(context);
|
||||
assert(() {
|
||||
if (newController == null) {
|
||||
throw FlutterError(
|
||||
@ -1411,7 +1411,7 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
bool get _controllerIsValid => _controller?.animation != null;
|
||||
|
||||
void _updateTabController() {
|
||||
final TabController? newController = widget.controller ?? DefaultTabController.of(context);
|
||||
final TabController? newController = widget.controller ?? DefaultTabController.maybeOf(context);
|
||||
assert(() {
|
||||
if (newController == null) {
|
||||
throw FlutterError(
|
||||
@ -1768,7 +1768,7 @@ class TabPageSelector extends StatelessWidget {
|
||||
final Color fixSelectedColor = selectedColor ?? Theme.of(context).colorScheme.secondary;
|
||||
final ColorTween selectedColorTween = ColorTween(begin: fixColor, end: fixSelectedColor);
|
||||
final ColorTween previousColorTween = ColorTween(begin: fixSelectedColor, end: fixColor);
|
||||
final TabController? tabController = controller ?? DefaultTabController.of(context);
|
||||
final TabController? tabController = controller ?? DefaultTabController.maybeOf(context);
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
assert(() {
|
||||
if (tabController == null) {
|
||||
|
@ -38,7 +38,12 @@ abstract class RenderAbstractViewport extends RenderObject {
|
||||
///
|
||||
/// If the object does not have a [RenderAbstractViewport] as an ancestor,
|
||||
/// this function returns null.
|
||||
static RenderAbstractViewport? of(RenderObject? object) {
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RenderAbstractViewport.of], which is similar to this method, but
|
||||
/// asserts if no [RenderAbstractViewport] ancestor is found.
|
||||
static RenderAbstractViewport? maybeOf(RenderObject? object) {
|
||||
while (object != null) {
|
||||
if (object is RenderAbstractViewport) {
|
||||
return object;
|
||||
@ -48,6 +53,35 @@ abstract class RenderAbstractViewport extends RenderObject {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns the [RenderAbstractViewport] that most tightly encloses the given
|
||||
/// render object.
|
||||
///
|
||||
/// If the object does not have a [RenderAbstractViewport] as an ancestor,
|
||||
/// this function will assert in debug mode, and throw an exception in release
|
||||
/// mode.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RenderAbstractViewport.maybeOf], which is similar to this method, but
|
||||
/// returns null if no [RenderAbstractViewport] ancestor is found.
|
||||
static RenderAbstractViewport of(RenderObject? object) {
|
||||
final RenderAbstractViewport? viewport = maybeOf(object);
|
||||
assert(() {
|
||||
if (viewport == null) {
|
||||
throw FlutterError(
|
||||
'RenderAbstractViewport.of() was called with a render object that was '
|
||||
'not a descendant of a RenderAbstractViewport.\n'
|
||||
'No RenderAbstractViewport render object ancestor could be found starting '
|
||||
'from the object that was passed to RenderAbstractViewport.of().\n'
|
||||
'The render object where the viewport search started was:\n'
|
||||
' $object',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return viewport!;
|
||||
}
|
||||
|
||||
/// Returns the offset that would be needed to reveal the `target`
|
||||
/// [RenderObject].
|
||||
///
|
||||
|
@ -72,19 +72,62 @@ class AutofillGroup extends StatefulWidget {
|
||||
this.onDisposeAction = AutofillContextAction.commit,
|
||||
}) : assert(child != null);
|
||||
|
||||
/// Returns the closest [AutofillGroupState] which encloses the given context.
|
||||
/// Returns the [AutofillGroupState] of the closest [AutofillGroup] widget
|
||||
/// which encloses the given context, or null if one cannot be found.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [AutofillGroup] in the [context], if there is one.
|
||||
///
|
||||
/// {@macro flutter.widgets.AutofillGroupState}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AutofillGroup.of], which is similar to this method, but asserts if an
|
||||
/// [AutofillGroup] cannot be found.
|
||||
/// * [EditableTextState], where this method is used to retrieve the closest
|
||||
/// [AutofillGroupState].
|
||||
static AutofillGroupState? of(BuildContext context) {
|
||||
static AutofillGroupState? maybeOf(BuildContext context) {
|
||||
final _AutofillScope? scope = context.dependOnInheritedWidgetOfExactType<_AutofillScope>();
|
||||
return scope?._scope;
|
||||
}
|
||||
|
||||
/// Returns the [AutofillGroupState] of the closest [AutofillGroup] widget
|
||||
/// which encloses the given context.
|
||||
///
|
||||
/// If no instance is found, this method will assert in debug mode and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [AutofillGroup] in the [context].
|
||||
///
|
||||
/// {@macro flutter.widgets.AutofillGroupState}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AutofillGroup.maybeOf], which is similar to this method, but returns
|
||||
/// null if an [AutofillGroup] cannot be found.
|
||||
/// * [EditableTextState], where this method is used to retrieve the closest
|
||||
/// [AutofillGroupState].
|
||||
static AutofillGroupState of(BuildContext context) {
|
||||
final AutofillGroupState? groupState = maybeOf(context);
|
||||
assert(() {
|
||||
if (groupState == null) {
|
||||
throw FlutterError(
|
||||
'AutofillGroup.of() was called with a context that does not contain an '
|
||||
'AutofillGroup widget.\n'
|
||||
'No AutofillGroup widget ancestor could be found starting from the '
|
||||
'context that was passed to AutofillGroup.of(). This can happen '
|
||||
'because you are using a widget that looks for an AutofillGroup '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return groupState!;
|
||||
}
|
||||
|
||||
/// {@macro flutter.widgets.ProxyWidget.child}
|
||||
final Widget child;
|
||||
|
||||
@ -171,7 +214,7 @@ class AutofillGroupState extends State<AutofillGroup> with AutofillScopeMixin {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_isTopmostAutofillGroup = AutofillGroup.of(context) == null;
|
||||
_isTopmostAutofillGroup = AutofillGroup.maybeOf(context) == null;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2373,7 +2373,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
|
||||
final AutofillGroupState? newAutofillGroup = AutofillGroup.of(context);
|
||||
final AutofillGroupState? newAutofillGroup = AutofillGroup.maybeOf(context);
|
||||
if (currentAutofillScope != newAutofillGroup) {
|
||||
_currentAutofillScope?.unregister(autofillId);
|
||||
_currentAutofillScope = newAutofillGroup;
|
||||
@ -3481,7 +3481,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
textAlign: widget.textAlign,
|
||||
textDirection: _textDirection,
|
||||
textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
|
||||
textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
|
||||
textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context),
|
||||
locale: widget.locale,
|
||||
structStyle: widget.strutStyle,
|
||||
placeholder: _placeholderLocation,
|
||||
@ -4150,7 +4150,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
textAlign: widget.textAlign,
|
||||
textDirection: _textDirection,
|
||||
locale: widget.locale,
|
||||
textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
|
||||
textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context),
|
||||
textWidthBasis: widget.textWidthBasis,
|
||||
obscuringCharacter: widget.obscuringCharacter,
|
||||
obscureText: widget.obscureText,
|
||||
|
@ -623,7 +623,7 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
||||
// Returns true if successfully popped the history.
|
||||
bool popOrInvalidate(TraversalDirection direction) {
|
||||
final FocusNode lastNode = policyData.history.removeLast().node;
|
||||
if (Scrollable.of(lastNode.context!) != Scrollable.of(primaryFocus!.context!)) {
|
||||
if (Scrollable.maybeOf(lastNode.context!) != Scrollable.maybeOf(primaryFocus!.context!)) {
|
||||
invalidateScopeData(nearestScope);
|
||||
return false;
|
||||
}
|
||||
@ -741,7 +741,7 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
||||
return true;
|
||||
}
|
||||
FocusNode? found;
|
||||
final ScrollableState? focusedScrollable = Scrollable.of(focusedChild.context!);
|
||||
final ScrollableState? focusedScrollable = Scrollable.maybeOf(focusedChild.context!);
|
||||
switch (direction) {
|
||||
case TraversalDirection.down:
|
||||
case TraversalDirection.up:
|
||||
@ -751,7 +751,7 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
||||
nearestScope.traversalDescendants,
|
||||
);
|
||||
if (focusedScrollable != null && !focusedScrollable.position.atEdge) {
|
||||
final Iterable<FocusNode> filteredEligibleNodes = eligibleNodes!.where((FocusNode node) => Scrollable.of(node.context!) == focusedScrollable);
|
||||
final Iterable<FocusNode> filteredEligibleNodes = eligibleNodes!.where((FocusNode node) => Scrollable.maybeOf(node.context!) == focusedScrollable);
|
||||
if (filteredEligibleNodes.isNotEmpty) {
|
||||
eligibleNodes = filteredEligibleNodes;
|
||||
}
|
||||
@ -783,7 +783,7 @@ mixin DirectionalFocusTraversalPolicyMixin on FocusTraversalPolicy {
|
||||
case TraversalDirection.left:
|
||||
Iterable<FocusNode>? eligibleNodes = _sortAndFilterHorizontally(direction, focusedChild.rect, nearestScope);
|
||||
if (focusedScrollable != null && !focusedScrollable.position.atEdge) {
|
||||
final Iterable<FocusNode> filteredEligibleNodes = eligibleNodes!.where((FocusNode node) => Scrollable.of(node.context!) == focusedScrollable);
|
||||
final Iterable<FocusNode> filteredEligibleNodes = eligibleNodes!.where((FocusNode node) => Scrollable.maybeOf(node.context!) == focusedScrollable);
|
||||
if (filteredEligibleNodes.isNotEmpty) {
|
||||
eligibleNodes = filteredEligibleNodes;
|
||||
}
|
||||
|
@ -49,20 +49,66 @@ class Form extends StatefulWidget {
|
||||
}) : assert(child != null),
|
||||
autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled;
|
||||
|
||||
/// Returns the closest [FormState] which encloses the given context,
|
||||
/// or null if there is no such form.
|
||||
/// Returns the [FormState] of the closest [Form] widget which encloses the
|
||||
/// given context, or null if none is found.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// FormState form = Form.of(context)!;
|
||||
/// form.save();
|
||||
/// FormState? form = Form.maybeOf(context);
|
||||
/// form?.save();
|
||||
/// ```
|
||||
static FormState? of(BuildContext context) {
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest [Form] in the
|
||||
/// [context], if there is one.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Form.of], which is similar to this method, but asserts if no [Form]
|
||||
/// ancestor is found.
|
||||
static FormState? maybeOf(BuildContext context) {
|
||||
final _FormScope? scope = context.dependOnInheritedWidgetOfExactType<_FormScope>();
|
||||
return scope?._formState;
|
||||
}
|
||||
|
||||
/// Returns the [FormState] of the closest [Form] widget which encloses the
|
||||
/// given context.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// FormState form = Form.of(context);
|
||||
/// form.save();
|
||||
/// ```
|
||||
///
|
||||
/// If no [Form] ancestor is found, this will assert in debug mode, and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest [Form] in the
|
||||
/// [context].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Form.maybeOf], which is similar to this method, but returns null if no
|
||||
/// [Form] ancestor is found.
|
||||
static FormState of(BuildContext context) {
|
||||
final FormState? formState = maybeOf(context);
|
||||
assert(() {
|
||||
if (formState == null) {
|
||||
throw FlutterError(
|
||||
'Form.of() was called with a context that does not contain a Form widget.\n'
|
||||
'No Form widget ancestor could be found starting from the context that '
|
||||
'was passed to Form.of(). This can happen because you are using a widget '
|
||||
'that looks for a Form ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return formState!;
|
||||
}
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// This is the root of the widget hierarchy that contains this form.
|
||||
@ -380,7 +426,7 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
|
||||
_hasInteractedByUser.value = false;
|
||||
_errorText.value = null;
|
||||
});
|
||||
Form.of(context)?._fieldDidChange();
|
||||
Form.maybeOf(context)?._fieldDidChange();
|
||||
}
|
||||
|
||||
/// Calls [FormField.validator] to set the [errorText]. Returns true if there
|
||||
@ -414,7 +460,7 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
|
||||
_value = value;
|
||||
_hasInteractedByUser.value = true;
|
||||
});
|
||||
Form.of(context)?._fieldDidChange();
|
||||
Form.maybeOf(context)?._fieldDidChange();
|
||||
}
|
||||
|
||||
/// Sets the value associated with this form field.
|
||||
@ -441,7 +487,7 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
|
||||
|
||||
@override
|
||||
void deactivate() {
|
||||
Form.of(context)?._unregister(this);
|
||||
Form.maybeOf(context)?._unregister(this);
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@ -461,7 +507,7 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Form.of(context)?._register(this);
|
||||
Form.maybeOf(context)?._register(this);
|
||||
return widget.builder(this);
|
||||
}
|
||||
}
|
||||
|
@ -1605,8 +1605,12 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
|
||||
///
|
||||
/// final Color color;
|
||||
///
|
||||
/// static FrogColor? maybeOf(BuildContext context) {
|
||||
/// return context.dependOnInheritedWidgetOfExactType<FrogColor>();
|
||||
/// }
|
||||
///
|
||||
/// static FrogColor of(BuildContext context) {
|
||||
/// final FrogColor? result = context.dependOnInheritedWidgetOfExactType<FrogColor>();
|
||||
/// final FrogColor? result = maybeOf(context);
|
||||
/// assert(result != null, 'No FrogColor found in context');
|
||||
/// return result!;
|
||||
/// }
|
||||
@ -1617,30 +1621,35 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// ## Implementing the `of` method
|
||||
/// ## Implementing the `of` and `maybeOf` methods
|
||||
///
|
||||
/// The convention is to provide a static method `of` on the [InheritedWidget]
|
||||
/// which does the call to [BuildContext.dependOnInheritedWidgetOfExactType]. This
|
||||
/// allows the class to define its own fallback logic in case there isn't
|
||||
/// a widget in scope. In the example above, the value returned will be
|
||||
/// null in that case, but it could also have defaulted to a value.
|
||||
/// The convention is to provide two static methods, `of` and `maybeOf`, on the
|
||||
/// [InheritedWidget] which call
|
||||
/// [BuildContext.dependOnInheritedWidgetOfExactType]. This allows the class to
|
||||
/// define its own fallback logic in case there isn't a widget in scope.
|
||||
///
|
||||
/// Sometimes, the `of` method returns the data rather than the inherited
|
||||
/// widget; for example, in this case it could have returned a [Color] instead
|
||||
/// of the `FrogColor` widget.
|
||||
/// The `of` method typically returns a non-nullable instance and asserts if the
|
||||
/// [InheritedWidget] isn't found, and the `maybeOf` method returns a nullable
|
||||
/// instance, and returns null if the [InheritedWidget] isn't found. The `of`
|
||||
/// method is typically implemented by calling `maybeOf` internally.
|
||||
///
|
||||
/// Sometimes, the `of` and `maybeOf` methods return some data rather than the
|
||||
/// inherited widget itself; for example, in this case it could have returned a
|
||||
/// [Color] instead of the `FrogColor` widget.
|
||||
///
|
||||
/// Occasionally, the inherited widget is an implementation detail of another
|
||||
/// class, and is therefore private. The `of` method in that case is typically
|
||||
/// put on the public class instead. For example, [Theme] is implemented as a
|
||||
/// [StatelessWidget] that builds a private inherited widget; [Theme.of] looks
|
||||
/// for that inherited widget using [BuildContext.dependOnInheritedWidgetOfExactType]
|
||||
/// and then returns the [ThemeData].
|
||||
/// class, and is therefore private. The `of` and `maybeOf` methods in that case
|
||||
/// are typically implemented on the public class instead. For example, [Theme]
|
||||
/// is implemented as a [StatelessWidget] that builds a private inherited
|
||||
/// widget; [Theme.of] looks for that private inherited widget using
|
||||
/// [BuildContext.dependOnInheritedWidgetOfExactType] and then returns the
|
||||
/// [ThemeData] inside it.
|
||||
///
|
||||
/// ## Calling the `of` method
|
||||
/// ## Calling the `of` or `maybeOf` methods
|
||||
///
|
||||
/// When using the `of` method, the `context` must be a descendant of the
|
||||
/// [InheritedWidget], meaning it must be "below" the [InheritedWidget] in the
|
||||
/// tree.
|
||||
/// When using the `of` or `maybeOf` methods, the `context` must be a descendant
|
||||
/// of the [InheritedWidget], meaning it must be "below" the [InheritedWidget]
|
||||
/// in the tree.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
@ -1674,8 +1683,9 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// In this example, the `context` used is the one from the `MyOtherPage` widget,
|
||||
/// which is a parent of the `FrogColor` widget, so this does not work.
|
||||
/// In this example, the `context` used is the one from the `MyOtherPage`
|
||||
/// widget, which is a parent of the `FrogColor` widget, so this does not work,
|
||||
/// and will assert when `FrogColor.of` is called.
|
||||
///
|
||||
/// ```dart
|
||||
/// // continuing from previous example...
|
||||
@ -1697,21 +1707,20 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
/// {@youtube 560 315 https://www.youtube.com/watch?v=1t-8rBCGBYw}
|
||||
/// {@end-tool} {@youtube 560 315 https://www.youtube.com/watch?v=1t-8rBCGBYw}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [StatefulWidget] and [State], for widgets that can build differently
|
||||
/// several times over their lifetime.
|
||||
/// * [StatelessWidget], for widgets that always build the same way given a
|
||||
/// particular configuration and ambient state.
|
||||
/// * [Widget], for an overview of widgets in general.
|
||||
/// * [InheritedNotifier], an inherited widget whose value can be a
|
||||
/// [Listenable], and which will notify dependents whenever the value
|
||||
/// sends notifications.
|
||||
/// * [InheritedModel], an inherited widget that allows clients to subscribe
|
||||
/// to changes for subparts of the value.
|
||||
/// * [StatefulWidget] and [State], for widgets that can build differently
|
||||
/// several times over their lifetime.
|
||||
/// * [StatelessWidget], for widgets that always build the same way given a
|
||||
/// particular configuration and ambient state.
|
||||
/// * [Widget], for an overview of widgets in general.
|
||||
/// * [InheritedNotifier], an inherited widget whose value can be a
|
||||
/// [Listenable], and which will notify dependents whenever the value sends
|
||||
/// notifications.
|
||||
/// * [InheritedModel], an inherited widget that allows clients to subscribe to
|
||||
/// changes for subparts of the value.
|
||||
abstract class InheritedWidget extends ProxyWidget {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
|
@ -6,53 +6,61 @@ import 'dart:collection';
|
||||
|
||||
import 'framework.dart';
|
||||
|
||||
/// An [InheritedWidget] that's intended to be used as the base class for
|
||||
/// models whose dependents may only depend on one part or "aspect" of the
|
||||
/// overall model.
|
||||
/// An [InheritedWidget] that's intended to be used as the base class for models
|
||||
/// whose dependents may only depend on one part or "aspect" of the overall
|
||||
/// model.
|
||||
///
|
||||
/// An inherited widget's dependents are unconditionally rebuilt when the
|
||||
/// inherited widget changes per [InheritedWidget.updateShouldNotify].
|
||||
/// This widget is similar except that dependents aren't rebuilt
|
||||
/// unconditionally.
|
||||
/// inherited widget changes per [InheritedWidget.updateShouldNotify]. This
|
||||
/// widget is similar except that dependents aren't rebuilt unconditionally.
|
||||
///
|
||||
/// Widgets that depend on an [InheritedModel] qualify their dependence
|
||||
/// with a value that indicates what "aspect" of the model they depend
|
||||
/// on. When the model is rebuilt, dependents will also be rebuilt, but
|
||||
/// only if there was a change in the model that corresponds to the aspect
|
||||
/// they provided.
|
||||
/// Widgets that depend on an [InheritedModel] qualify their dependence with a
|
||||
/// value that indicates what "aspect" of the model they depend on. When the
|
||||
/// model is rebuilt, dependents will also be rebuilt, but only if there was a
|
||||
/// change in the model that corresponds to the aspect they provided.
|
||||
///
|
||||
/// The type parameter `T` is the type of the model aspect objects.
|
||||
///
|
||||
/// {@youtube 560 315 https://www.youtube.com/watch?v=ml5uefGgkaA}
|
||||
///
|
||||
/// Widgets create a dependency on an [InheritedModel] with a static method:
|
||||
/// [InheritedModel.inheritFrom]. This method's `context` parameter
|
||||
/// defines the subtree that will be rebuilt when the model changes.
|
||||
/// Typically the `inheritFrom` method is called from a model-specific
|
||||
/// static `of` method. For example:
|
||||
/// [InheritedModel.inheritFrom]. This method's `context` parameter defines the
|
||||
/// subtree that will be rebuilt when the model changes. Typically the
|
||||
/// `inheritFrom` method is called from a model-specific static `maybeOf` or
|
||||
/// `of` methods, a convention that is present in many Flutter framework classes
|
||||
/// which look things up. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// class MyModel extends InheritedModel<String> {
|
||||
/// const MyModel({super.key, required super.child});
|
||||
///
|
||||
/// // ...
|
||||
/// static MyModel? of(BuildContext context, String aspect) {
|
||||
/// static MyModel? maybeOf(BuildContext context, [String? aspect]) {
|
||||
/// return InheritedModel.inheritFrom<MyModel>(context, aspect: aspect);
|
||||
/// }
|
||||
///
|
||||
/// // ...
|
||||
/// static MyModel of(BuildContext context, [String? aspect]) {
|
||||
/// final MyModel? result = maybeOf(context, aspect);
|
||||
/// assert(result != null, 'Unable to find an instance of MyModel...');
|
||||
/// return result!;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Calling `MyModel.of(context, 'foo')` means that `context` should only
|
||||
/// be rebuilt when the `foo` aspect of `MyModel` changes. If the aspect
|
||||
/// is null, then the model supports all aspects.
|
||||
/// Calling `MyModel.of(context, 'foo')` or `MyModel.maybeOf(context,
|
||||
/// 'foo')` means that `context` should only be rebuilt when the `foo` aspect of
|
||||
/// `MyModel` changes. If the `aspect` is null, then the model supports all
|
||||
/// aspects.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// When the inherited model is rebuilt the [updateShouldNotify] and
|
||||
/// [updateShouldNotifyDependent] methods are used to decide what
|
||||
/// should be rebuilt. If [updateShouldNotify] returns true, then the
|
||||
/// inherited model's [updateShouldNotifyDependent] method is tested for
|
||||
/// each dependent and the set of aspect objects it depends on.
|
||||
/// The [updateShouldNotifyDependent] method must compare the set of aspect
|
||||
/// dependencies with the changes in the model itself. For example:
|
||||
/// [updateShouldNotifyDependent] methods are used to decide what should be
|
||||
/// rebuilt. If [updateShouldNotify] returns true, then the inherited model's
|
||||
/// [updateShouldNotifyDependent] method is tested for each dependent and the
|
||||
/// set of aspect objects it depends on. The [updateShouldNotifyDependent]
|
||||
/// method must compare the set of aspect dependencies with the changes in the
|
||||
/// model itself. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// class ABModel extends InheritedModel<String> {
|
||||
@ -85,26 +93,26 @@ import 'framework.dart';
|
||||
/// In the previous example the dependencies checked by
|
||||
/// [updateShouldNotifyDependent] are just the aspect strings passed to
|
||||
/// `dependOnInheritedWidgetOfExactType`. They're represented as a [Set] because
|
||||
/// one Widget can depend on more than one aspect of the model.
|
||||
/// If a widget depends on the model but doesn't specify an aspect,
|
||||
/// then changes in the model will cause the widget to be rebuilt
|
||||
/// unconditionally.
|
||||
/// one Widget can depend on more than one aspect of the model. If a widget
|
||||
/// depends on the model but doesn't specify an aspect, then changes in the
|
||||
/// model will cause the widget to be rebuilt unconditionally.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This example shows how to implement [InheritedModel] to rebuild a
|
||||
/// widget based on a qualified dependence. When tapped on the "Resize Logo" button
|
||||
/// only the logo widget is rebuilt while the background widget remains unaffected.
|
||||
/// This example shows how to implement [InheritedModel] to rebuild a widget
|
||||
/// based on a qualified dependence. When tapped on the "Resize Logo" button
|
||||
/// only the logo widget is rebuilt while the background widget remains
|
||||
/// unaffected.
|
||||
///
|
||||
/// ** See code in examples/api/lib/widgets/inherited_model/inherited_model.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [InheritedWidget], an inherited widget that only notifies dependents
|
||||
/// when its value is different.
|
||||
/// * [InheritedNotifier], an inherited widget whose value can be a
|
||||
/// [Listenable], and which will notify dependents whenever the value
|
||||
/// sends notifications.
|
||||
/// * [InheritedWidget], an inherited widget that only notifies dependents when
|
||||
/// its value is different.
|
||||
/// * [InheritedNotifier], an inherited widget whose value can be a
|
||||
/// [Listenable], and which will notify dependents whenever the value sends
|
||||
/// notifications.
|
||||
abstract class InheritedModel<T> extends InheritedWidget {
|
||||
/// Creates an inherited widget that supports dependencies qualified by
|
||||
/// "aspects", i.e. a descendant widget can indicate that it should
|
||||
|
@ -689,12 +689,53 @@ class HeroControllerScope extends InheritedWidget {
|
||||
final HeroController? controller;
|
||||
|
||||
/// Retrieves the [HeroController] from the closest [HeroControllerScope]
|
||||
/// ancestor.
|
||||
static HeroController? of(BuildContext context) {
|
||||
/// ancestor, or null if none exists.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [HeroControllerScope] in the [context], if there is one.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [HeroControllerScope.of], which is similar to this method, but asserts
|
||||
/// if no [HeroControllerScope] ancestor is found.
|
||||
static HeroController? maybeOf(BuildContext context) {
|
||||
final HeroControllerScope? host = context.dependOnInheritedWidgetOfExactType<HeroControllerScope>();
|
||||
return host?.controller;
|
||||
}
|
||||
|
||||
/// Retrieves the [HeroController] from the closest [HeroControllerScope]
|
||||
/// ancestor.
|
||||
///
|
||||
/// If no ancestor is found, this method will assert in debug mode, and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [HeroControllerScope] in the [context].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [HeroControllerScope.maybeOf], which is similar to this method, but
|
||||
/// returns null if no [HeroControllerScope] ancestor is found.
|
||||
static HeroController of(BuildContext context) {
|
||||
final HeroController? controller = maybeOf(context);
|
||||
assert(() {
|
||||
if (controller == null) {
|
||||
throw FlutterError(
|
||||
'HeroControllerScope.of() was called with a context that does not contain a '
|
||||
'HeroControllerScope widget.\n'
|
||||
'No HeroControllerScope widget ancestor could be found starting from the '
|
||||
'context that was passed to HeroControllerScope.of(). This can happen '
|
||||
'because you are using a widget that looks for a HeroControllerScope '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return controller!;
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(HeroControllerScope oldWidget) {
|
||||
return oldWidget.controller != controller;
|
||||
@ -3350,7 +3391,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_updateHeroController(HeroControllerScope.of(context));
|
||||
_updateHeroController(HeroControllerScope.maybeOf(context));
|
||||
for (final _RouteEntry entry in _history) {
|
||||
entry.route.changedExternalState();
|
||||
}
|
||||
|
@ -1088,7 +1088,7 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
|
||||
|
||||
void updateParent() {
|
||||
_outerPosition?.setParent(
|
||||
_parent ?? PrimaryScrollController.of(_state.context),
|
||||
_parent ?? PrimaryScrollController.maybeOf(_state.context),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -174,22 +174,66 @@ class PageStorage extends StatelessWidget {
|
||||
/// The page storage bucket to use for this subtree.
|
||||
final PageStorageBucket bucket;
|
||||
|
||||
/// The bucket from the closest instance of this class that encloses the given context.
|
||||
/// The [PageStorageBucket] from the closest instance of a [PageStorage]
|
||||
/// widget that encloses the given context.
|
||||
///
|
||||
/// Returns null if none exists.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// PageStorageBucket bucket = PageStorage.of(context)!;
|
||||
/// PageStorageBucket? bucket = PageStorage.of(context);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be expensive (it walks the element tree).
|
||||
static PageStorageBucket? of(BuildContext context) {
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PageStorage.of], which is similar to this method, but
|
||||
/// asserts if no [PageStorage] ancestor is found.
|
||||
static PageStorageBucket? maybeOf(BuildContext context) {
|
||||
final PageStorage? widget = context.findAncestorWidgetOfExactType<PageStorage>();
|
||||
return widget?.bucket;
|
||||
}
|
||||
|
||||
/// The [PageStorageBucket] from the closest instance of a [PageStorage]
|
||||
/// widget that encloses the given context.
|
||||
///
|
||||
/// If no ancestor is found, this method will assert in debug mode, and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// PageStorageBucket bucket = PageStorage.of(context);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be expensive (it walks the element tree).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PageStorage.maybeOf], which is similar to this method, but
|
||||
/// returns null if no [PageStorage] ancestor is found.
|
||||
static PageStorageBucket of(BuildContext context) {
|
||||
final PageStorageBucket? bucket = maybeOf(context);
|
||||
assert(() {
|
||||
if (bucket == null) {
|
||||
throw FlutterError(
|
||||
'PageStorage.of() was called with a context that does not contain a '
|
||||
'PageStorage widget.\n'
|
||||
'No PageStorage widget ancestor could be found starting from the '
|
||||
'context that was passed to PageStorage.of(). This can happen '
|
||||
'because you are using a widget that looks for a PageStorage '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return bucket!;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => child;
|
||||
}
|
||||
|
@ -403,13 +403,13 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
|
||||
|
||||
@override
|
||||
void saveScrollOffset() {
|
||||
PageStorage.of(context.storageContext)?.writeState(context.storageContext, _cachedPage ?? getPageFromPixels(pixels, viewportDimension));
|
||||
PageStorage.maybeOf(context.storageContext)?.writeState(context.storageContext, _cachedPage ?? getPageFromPixels(pixels, viewportDimension));
|
||||
}
|
||||
|
||||
@override
|
||||
void restoreScrollOffset() {
|
||||
if (!hasPixels) {
|
||||
final double? value = PageStorage.of(context.storageContext)?.readState(context.storageContext) as double?;
|
||||
final double? value = PageStorage.maybeOf(context.storageContext)?.readState(context.storageContext) as double?;
|
||||
if (value != null) {
|
||||
_pageToUseOnStartup = value;
|
||||
}
|
||||
|
@ -125,11 +125,52 @@ class PrimaryScrollController extends InheritedWidget {
|
||||
///
|
||||
/// Returns null if there is no [ScrollController] associated with the given
|
||||
/// context.
|
||||
static ScrollController? of(BuildContext context) {
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [PrimaryScrollController] in the [context], if there is one.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PrimaryScrollController.maybeOf], which is similar to this method, but
|
||||
/// asserts if no [PrimaryScrollController] ancestor is found.
|
||||
static ScrollController? maybeOf(BuildContext context) {
|
||||
final PrimaryScrollController? result = context.dependOnInheritedWidgetOfExactType<PrimaryScrollController>();
|
||||
return result?.controller;
|
||||
}
|
||||
|
||||
/// Returns the [ScrollController] most closely associated with the given
|
||||
/// context.
|
||||
///
|
||||
/// If no ancestor is found, this method will assert in debug mode, and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [PrimaryScrollController] in the [context].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PrimaryScrollController.maybeOf], which is similar to this method, but
|
||||
/// returns null if no [PrimaryScrollController] ancestor is found.
|
||||
static ScrollController of(BuildContext context) {
|
||||
final ScrollController? controller = maybeOf(context);
|
||||
assert(() {
|
||||
if (controller == null) {
|
||||
throw FlutterError(
|
||||
'PrimaryScrollController.of() was called with a context that does not contain a '
|
||||
'PrimaryScrollController widget.\n'
|
||||
'No PrimaryScrollController widget ancestor could be found starting from the '
|
||||
'context that was passed to PrimaryScrollController.of(). This can happen '
|
||||
'because you are using a widget that looks for a PrimaryScrollController '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return controller!;
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(PrimaryScrollController oldWidget) => controller != oldWidget.controller;
|
||||
|
||||
|
@ -609,7 +609,7 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_scrollable = Scrollable.of(context)!;
|
||||
_scrollable = Scrollable.of(context);
|
||||
if (_autoScroller?.scrollable != _scrollable) {
|
||||
_autoScroller?.stopAutoScroll();
|
||||
_autoScroller = EdgeDraggingAutoScroller(
|
||||
|
@ -65,18 +65,63 @@ class RestorationScope extends StatefulWidget {
|
||||
/// Returns the [RestorationBucket] inserted into the widget tree by the
|
||||
/// closest ancestor [RestorationScope] of `context`.
|
||||
///
|
||||
/// {@template flutter.widgets.restoration.RestorationScope.bucket_warning}
|
||||
/// To avoid accidentally overwriting data already stored in the bucket by its
|
||||
/// owner, data should not be stored directly in the bucket returned by this
|
||||
/// method. Instead, consider claiming a child bucket from the returned bucket
|
||||
/// (via [RestorationBucket.claimChild]) and store the restoration data in
|
||||
/// that child.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// This method returns null if state restoration is turned off for this
|
||||
/// subtree.
|
||||
static RestorationBucket? of(BuildContext context) {
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [RestorationScope] in the [context], if there is one.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RestorationScope.maybeOf], which is similar to this method, but asserts
|
||||
/// if no [RestorationScope] ancestor is found.
|
||||
static RestorationBucket? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<UnmanagedRestorationScope>()?.bucket;
|
||||
}
|
||||
|
||||
/// Returns the [RestorationBucket] inserted into the widget tree by the
|
||||
/// closest ancestor [RestorationScope] of `context`.
|
||||
///
|
||||
/// {@macro flutter.widgets.restoration.RestorationScope.bucket_warning}
|
||||
///
|
||||
/// This method will assert in debug mode and throw an exception in release
|
||||
/// mode if state restoration is turned off for this subtree.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [RestorationScope] in the [context].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RestorationScope.maybeOf], which is similar to this method, but returns
|
||||
/// null if no [RestorationScope] ancestor is found.
|
||||
static RestorationBucket of(BuildContext context) {
|
||||
final RestorationBucket? bucket = maybeOf(context);
|
||||
assert(() {
|
||||
if (bucket == null) {
|
||||
throw FlutterError(
|
||||
'RestorationScope.of() was called with a context that does not contain a '
|
||||
'RestorationScope widget.\n'
|
||||
'No RestorationScope widget ancestor could be found starting from the '
|
||||
'context that was passed to RestorationScope.of(). This can happen '
|
||||
'because you are using a widget that looks for a RestorationScope '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return bucket!;
|
||||
}
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// {@macro flutter.widgets.ProxyWidget.child}
|
||||
@ -250,7 +295,7 @@ class _RootRestorationScopeState extends State<RootRestorationScope> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_ancestorBucket = RestorationScope.of(context);
|
||||
_ancestorBucket = RestorationScope.maybeOf(context);
|
||||
_loadRootBucketIfNecessary();
|
||||
_okToRenderBlankContainer ??= widget.restorationId != null && _needsRootBucketInserted;
|
||||
}
|
||||
@ -834,7 +879,7 @@ mixin RestorationMixin<S extends StatefulWidget> on State<S> {
|
||||
if (restorationId == null) {
|
||||
return false;
|
||||
}
|
||||
final RestorationBucket? potentialNewParent = RestorationScope.of(context);
|
||||
final RestorationBucket? potentialNewParent = RestorationScope.maybeOf(context);
|
||||
return potentialNewParent != _currentParent && (potentialNewParent?.isReplacing ?? false);
|
||||
}
|
||||
|
||||
@ -850,7 +895,7 @@ mixin RestorationMixin<S extends StatefulWidget> on State<S> {
|
||||
|
||||
final RestorationBucket? oldBucket = _bucket;
|
||||
final bool needsRestore = restorePending;
|
||||
_currentParent = RestorationScope.of(context);
|
||||
_currentParent = RestorationScope.maybeOf(context);
|
||||
|
||||
final bool didReplaceBucket = _updateBucketIfNecessary(parent: _currentParent, restorePending: needsRestore);
|
||||
|
||||
|
@ -45,13 +45,13 @@ class _ListenerEntry extends LinkedListEntry<_ListenerEntry> {
|
||||
/// To add a listener to a [ScrollNotificationObserver] ancestor:
|
||||
///
|
||||
/// ```dart
|
||||
/// ScrollNotificationObserver.of(context)!.addListener(_listener);
|
||||
/// ScrollNotificationObserver.of(context).addListener(_listener);
|
||||
/// ```
|
||||
///
|
||||
/// To remove the listener from a [ScrollNotificationObserver] ancestor:
|
||||
///
|
||||
/// ```dart
|
||||
/// ScrollNotificationObserver.of(context)!.removeListener(_listener);
|
||||
/// ScrollNotificationObserver.of(context).removeListener(_listener);
|
||||
/// ```
|
||||
///
|
||||
/// Stateful widgets that share an ancestor [ScrollNotificationObserver] typically
|
||||
@ -85,11 +85,52 @@ class ScrollNotificationObserver extends StatefulWidget {
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [ScrollNotificationObserver] widget, then null is returned.
|
||||
static ScrollNotificationObserverState? of(BuildContext context) {
|
||||
/// If there is no enclosing [ScrollNotificationObserver] widget, then null is
|
||||
/// returned.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [ScrollNotificationObserver] in the [context], if there is one.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollNotificationObserver.of], which is similar to this method, but
|
||||
/// asserts if no [ScrollNotificationObserver] ancestor is found.
|
||||
static ScrollNotificationObserverState? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<_ScrollNotificationObserverScope>()?._scrollNotificationObserverState;
|
||||
}
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If no ancestor is found, this method will assert in debug mode, and throw
|
||||
/// an exception in release mode.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [ScrollNotificationObserver] in the [context].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ScrollNotificationObserver.maybeOf], which is similar to this method,
|
||||
/// but returns null if no [ScrollNotificationObserver] ancestor is found.
|
||||
static ScrollNotificationObserverState of(BuildContext context) {
|
||||
final ScrollNotificationObserverState? observerState = maybeOf(context);
|
||||
assert(() {
|
||||
if (observerState == null) {
|
||||
throw FlutterError(
|
||||
'ScrollNotificationObserver.of() was called with a context that does not contain a '
|
||||
'ScrollNotificationObserver widget.\n'
|
||||
'No ScrollNotificationObserver widget ancestor could be found starting from the '
|
||||
'context that was passed to ScrollNotificationObserver.of(). This can happen '
|
||||
'because you are using a widget that looks for a ScrollNotificationObserver '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return observerState!;
|
||||
}
|
||||
|
||||
@override
|
||||
ScrollNotificationObserverState createState() => ScrollNotificationObserverState();
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
||||
// TODO(goderbauer): Deprecate this when state restoration supports all features of PageStorage.
|
||||
@protected
|
||||
void saveScrollOffset() {
|
||||
PageStorage.of(context.storageContext)?.writeState(context.storageContext, pixels);
|
||||
PageStorage.maybeOf(context.storageContext)?.writeState(context.storageContext, pixels);
|
||||
}
|
||||
|
||||
/// Called whenever the [ScrollPosition] is created, to restore the scroll
|
||||
@ -424,7 +424,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
||||
@protected
|
||||
void restoreScrollOffset() {
|
||||
if (!hasPixels) {
|
||||
final double? value = PageStorage.of(context.storageContext)?.readState(context.storageContext) as double?;
|
||||
final double? value = PageStorage.maybeOf(context.storageContext)?.readState(context.storageContext) as double?;
|
||||
if (value != null) {
|
||||
correctPixels(value);
|
||||
}
|
||||
@ -703,7 +703,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
||||
}) {
|
||||
assert(alignmentPolicy != null);
|
||||
assert(object.attached);
|
||||
final RenderAbstractViewport viewport = RenderAbstractViewport.of(object)!;
|
||||
final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
|
||||
assert(viewport != null);
|
||||
|
||||
Rect? targetRect;
|
||||
|
@ -411,7 +411,7 @@ abstract class ScrollView extends StatelessWidget {
|
||||
?? controller == null && PrimaryScrollController.shouldInherit(context, scrollDirection);
|
||||
|
||||
final ScrollController? scrollController = effectivePrimary
|
||||
? PrimaryScrollController.of(context)
|
||||
? PrimaryScrollController.maybeOf(context)
|
||||
: controller;
|
||||
|
||||
final Scrollable scrollable = Scrollable(
|
||||
|
@ -289,21 +289,66 @@ class Scrollable extends StatefulWidget {
|
||||
properties.add(StringProperty('restorationId', restorationId));
|
||||
}
|
||||
|
||||
/// The state from the closest instance of this class that encloses the given context.
|
||||
/// The state from the closest instance of this class that encloses the given
|
||||
/// context, or null if none is found.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// ScrollableState scrollable = Scrollable.of(context)!;
|
||||
/// ScrollableState? scrollable = Scrollable.maybeOf(context);
|
||||
/// ```
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest [Scrollable]
|
||||
/// in the [context], if there is one.
|
||||
static ScrollableState? of(BuildContext context) {
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Scrollable.of], which is similar to this method, but asserts
|
||||
/// if no [Scrollable] ancestor is found.
|
||||
static ScrollableState? maybeOf(BuildContext context) {
|
||||
final _ScrollableScope? widget = context.dependOnInheritedWidgetOfExactType<_ScrollableScope>();
|
||||
return widget?.scrollable;
|
||||
}
|
||||
|
||||
/// The state from the closest instance of this class that encloses the given
|
||||
/// context.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// ScrollableState scrollable = Scrollable.of(context);
|
||||
/// ```
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest [Scrollable]
|
||||
/// in the [context].
|
||||
///
|
||||
/// If no [Scrollable] ancestor is found, then this method will assert in
|
||||
/// debug mode, and throw an exception in release mode.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Scrollable.maybeOf], which is similar to this method, but returns null
|
||||
/// if no [Scrollable] ancestor is found.
|
||||
static ScrollableState of(BuildContext context) {
|
||||
final ScrollableState? scrollableState = maybeOf(context);
|
||||
assert(() {
|
||||
if (scrollableState == null) {
|
||||
throw FlutterError(
|
||||
'Scrollable.of() was called with a context that does not contain a '
|
||||
'Scrollable widget.\n'
|
||||
'No Scrollable widget ancestor could be found starting from the '
|
||||
'context that was passed to Scrollable.of(). This can happen '
|
||||
'because you are using a widget that looks for a Scrollable '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return scrollableState!;
|
||||
}
|
||||
|
||||
/// Provides a heuristic to determine if expensive frame-bound tasks should be
|
||||
/// deferred for the [context] at a specific point in time.
|
||||
///
|
||||
@ -343,7 +388,7 @@ class Scrollable extends StatefulWidget {
|
||||
// the `targetRenderObject` invisible.
|
||||
// Also see https://github.com/flutter/flutter/issues/65100
|
||||
RenderObject? targetRenderObject;
|
||||
ScrollableState? scrollable = Scrollable.of(context);
|
||||
ScrollableState? scrollable = Scrollable.maybeOf(context);
|
||||
while (scrollable != null) {
|
||||
futures.add(scrollable.position.ensureVisible(
|
||||
context.findRenderObject()!,
|
||||
@ -356,7 +401,7 @@ class Scrollable extends StatefulWidget {
|
||||
|
||||
targetRenderObject = targetRenderObject ?? context.findRenderObject();
|
||||
context = scrollable.context;
|
||||
scrollable = Scrollable.of(context);
|
||||
scrollable = Scrollable.maybeOf(context);
|
||||
}
|
||||
|
||||
if (futures.isEmpty || duration == Duration.zero) {
|
||||
@ -1618,11 +1663,11 @@ class ScrollAction extends Action<ScrollIntent> {
|
||||
final bool contextIsValid = focus != null && focus.context != null;
|
||||
if (contextIsValid) {
|
||||
// Check for primary scrollable within the current context
|
||||
if (Scrollable.of(focus.context!) != null) {
|
||||
if (Scrollable.maybeOf(focus.context!) != null) {
|
||||
return true;
|
||||
}
|
||||
// Check for fallback scrollable with context from PrimaryScrollController
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.of(focus.context!);
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.maybeOf(focus.context!);
|
||||
return primaryScrollController != null && primaryScrollController.hasClients;
|
||||
}
|
||||
return false;
|
||||
@ -1709,11 +1754,11 @@ class ScrollAction extends Action<ScrollIntent> {
|
||||
|
||||
@override
|
||||
void invoke(ScrollIntent intent) {
|
||||
ScrollableState? state = Scrollable.of(primaryFocus!.context!);
|
||||
ScrollableState? state = Scrollable.maybeOf(primaryFocus!.context!);
|
||||
if (state == null) {
|
||||
final ScrollController? primaryScrollController = PrimaryScrollController.of(primaryFocus!.context!);
|
||||
final ScrollController primaryScrollController = PrimaryScrollController.of(primaryFocus!.context!);
|
||||
assert (() {
|
||||
if (primaryScrollController!.positions.length != 1) {
|
||||
if (primaryScrollController.positions.length != 1) {
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary(
|
||||
'A ScrollAction was invoked with the PrimaryScrollController, but '
|
||||
@ -1735,11 +1780,11 @@ class ScrollAction extends Action<ScrollIntent> {
|
||||
return true;
|
||||
}());
|
||||
|
||||
if (primaryScrollController!.position.context.notificationContext == null
|
||||
&& Scrollable.of(primaryScrollController.position.context.notificationContext!) == null) {
|
||||
if (primaryScrollController.position.context.notificationContext == null
|
||||
&& Scrollable.maybeOf(primaryScrollController.position.context.notificationContext!) == null) {
|
||||
return;
|
||||
}
|
||||
state = Scrollable.of(primaryScrollController.position.context.notificationContext!);
|
||||
state = Scrollable.maybeOf(primaryScrollController.position.context.notificationContext!);
|
||||
}
|
||||
assert(state != null, '$ScrollAction was invoked on a context that has no scrollable parent');
|
||||
assert(state!.position.hasPixels, 'Scrollable must be laid out before it can be scrolled via a ScrollAction');
|
||||
|
@ -1550,7 +1550,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
}
|
||||
|
||||
void _validateInteractions(AnimationStatus status) {
|
||||
final ScrollController? scrollController = widget.controller ?? PrimaryScrollController.of(context);
|
||||
final ScrollController? scrollController = widget.controller ?? PrimaryScrollController.maybeOf(context);
|
||||
if (status == AnimationStatus.dismissed) {
|
||||
assert(_fadeoutOpacityAnimation.value == 0.0);
|
||||
// We do not check for a valid scroll position if the scrollbar is not
|
||||
@ -1566,7 +1566,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
if (!mounted) {
|
||||
return true;
|
||||
}
|
||||
final ScrollController? scrollController = widget.controller ?? PrimaryScrollController.of(context);
|
||||
final ScrollController? scrollController = widget.controller ?? PrimaryScrollController.maybeOf(context);
|
||||
final bool tryPrimary = widget.controller == null;
|
||||
final String controllerForError = tryPrimary
|
||||
? 'PrimaryScrollController'
|
||||
@ -1788,7 +1788,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
@mustCallSuper
|
||||
void handleThumbPressStart(Offset localPosition) {
|
||||
assert(_debugCheckHasValidScrollPosition());
|
||||
_currentController = widget.controller ?? PrimaryScrollController.of(context);
|
||||
_currentController = widget.controller ?? PrimaryScrollController.maybeOf(context);
|
||||
final Axis? direction = getScrollbarDirection();
|
||||
if (direction == null) {
|
||||
return;
|
||||
@ -1835,7 +1835,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
void _handleTrackTapDown(TapDownDetails details) {
|
||||
// The Scrollbar should page towards the position of the tap on the track.
|
||||
assert(_debugCheckHasValidScrollPosition());
|
||||
_currentController = widget.controller ?? PrimaryScrollController.of(context);
|
||||
_currentController = widget.controller ?? PrimaryScrollController.maybeOf(context);
|
||||
|
||||
final ScrollPosition position = _currentController!.position;
|
||||
if (!position.physics.shouldAcceptUserOffset(position)) {
|
||||
@ -1844,7 +1844,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
|
||||
double scrollIncrement;
|
||||
// Is an increment calculator available?
|
||||
final ScrollIncrementCalculator? calculator = Scrollable.of(
|
||||
final ScrollIncrementCalculator? calculator = Scrollable.maybeOf(
|
||||
_currentController!.position.context.notificationContext!,
|
||||
)?.widget.incrementCalculator;
|
||||
if (calculator != null) {
|
||||
@ -1893,7 +1893,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
// ScrollController takes precedence over ScrollNotification
|
||||
bool _shouldUpdatePainter(Axis notificationAxis) {
|
||||
final ScrollController? scrollController = widget.controller ??
|
||||
PrimaryScrollController.of(context);
|
||||
PrimaryScrollController.maybeOf(context);
|
||||
// Only update the painter of this scrollbar if the notification
|
||||
// metrics do not conflict with the information we have from the scroll
|
||||
// controller.
|
||||
@ -1979,7 +1979,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
|
||||
Map<Type, GestureRecognizerFactory> get _gestures {
|
||||
final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
|
||||
final ScrollController? controller = widget.controller ?? PrimaryScrollController.of(context);
|
||||
final ScrollController? controller = widget.controller ?? PrimaryScrollController.maybeOf(context);
|
||||
if (controller == null || !enableGestures) {
|
||||
return gestures;
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ class SingleChildScrollView extends StatelessWidget {
|
||||
?? controller == null && PrimaryScrollController.shouldInherit(context, scrollDirection);
|
||||
|
||||
final ScrollController? scrollController = effectivePrimary
|
||||
? PrimaryScrollController.of(context)
|
||||
? PrimaryScrollController.maybeOf(context)
|
||||
: controller;
|
||||
|
||||
Widget scrollable = Scrollable(
|
||||
|
@ -212,7 +212,7 @@ class _FloatingHeaderState extends State<_FloatingHeader> {
|
||||
if (_position != null) {
|
||||
_position!.isScrollingNotifier.removeListener(_isScrollingListener);
|
||||
}
|
||||
_position = Scrollable.of(context)?.position;
|
||||
_position = Scrollable.maybeOf(context)?.position;
|
||||
if (_position != null) {
|
||||
_position!.isScrollingNotifier.addListener(_isScrollingListener);
|
||||
}
|
||||
|
@ -245,19 +245,67 @@ class DefaultTextHeightBehavior extends InheritedTheme {
|
||||
/// {@macro dart.ui.textHeightBehavior}
|
||||
final TextHeightBehavior textHeightBehavior;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
/// The closest instance of [DefaultTextHeightBehavior] that encloses the
|
||||
/// given context, or null if none is found.
|
||||
///
|
||||
/// If no such instance exists, this method will return `null`.
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [DefaultTextHeightBehavior] in the [context], if there is one.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// TextHeightBehavior defaultTextHeightBehavior = DefaultTextHeightBehavior.of(context)!;
|
||||
/// TextHeightBehavior? defaultTextHeightBehavior = DefaultTextHeightBehavior.of(context);
|
||||
/// ```
|
||||
static TextHeightBehavior? of(BuildContext context) {
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [DefaultTextHeightBehavior.maybeOf], which is similar to this method,
|
||||
/// but asserts if no [DefaultTextHeightBehavior] ancestor is found.
|
||||
static TextHeightBehavior? maybeOf(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<DefaultTextHeightBehavior>()?.textHeightBehavior;
|
||||
}
|
||||
|
||||
/// The closest instance of [DefaultTextHeightBehavior] that encloses the
|
||||
/// given context.
|
||||
///
|
||||
/// If no such instance exists, this method will assert in debug mode, and
|
||||
/// throw an exception in release mode.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// TextHeightBehavior defaultTextHeightBehavior = DefaultTextHeightBehavior.of(context);
|
||||
/// ```
|
||||
///
|
||||
/// Calling this method will create a dependency on the closest
|
||||
/// [DefaultTextHeightBehavior] in the [context].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [DefaultTextHeightBehavior.maybeOf], which is similar to this method,
|
||||
/// but returns null if no [DefaultTextHeightBehavior] ancestor is found.
|
||||
static TextHeightBehavior of(BuildContext context) {
|
||||
final TextHeightBehavior? behavior = maybeOf(context);
|
||||
assert(() {
|
||||
if (behavior == null) {
|
||||
throw FlutterError(
|
||||
'DefaultTextHeightBehavior.of() was called with a context that does not contain a '
|
||||
'DefaultTextHeightBehavior widget.\n'
|
||||
'No DefaultTextHeightBehavior widget ancestor could be found starting from the '
|
||||
'context that was passed to DefaultTextHeightBehavior.of(). This can happen '
|
||||
'because you are using a widget that looks for a DefaultTextHeightBehavior '
|
||||
'ancestor, but no such ancestor exists.\n'
|
||||
'The context used was:\n'
|
||||
' $context',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return behavior!;
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(DefaultTextHeightBehavior oldWidget) {
|
||||
return textHeightBehavior != oldWidget.textHeightBehavior;
|
||||
@ -564,7 +612,7 @@ class Text extends StatelessWidget {
|
||||
maxLines: maxLines ?? defaultTextStyle.maxLines,
|
||||
strutStyle: strutStyle,
|
||||
textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis,
|
||||
textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
|
||||
textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context),
|
||||
selectionRegistrar: registrar,
|
||||
selectionColor: selectionColor ?? DefaultSelectionStyle.of(context).selectionColor ?? DefaultSelectionStyle.defaultColor,
|
||||
text: TextSpan(
|
||||
|
@ -1893,7 +1893,7 @@ class TextSelectionGestureDetectorBuilder {
|
||||
final ScrollableState? scrollableState =
|
||||
delegate.editableTextKey.currentContext == null
|
||||
? null
|
||||
: Scrollable.of(delegate.editableTextKey.currentContext!);
|
||||
: Scrollable.maybeOf(delegate.editableTextKey.currentContext!);
|
||||
return scrollableState == null
|
||||
? 0.0
|
||||
: scrollableState.position.pixels;
|
||||
|
@ -51,7 +51,7 @@ Widget buildSliverAppBarApp({
|
||||
}
|
||||
|
||||
ScrollController primaryScrollController(WidgetTester tester) {
|
||||
return PrimaryScrollController.of(tester.element(find.byType(CustomScrollView)))!;
|
||||
return PrimaryScrollController.of(tester.element(find.byType(CustomScrollView)));
|
||||
}
|
||||
|
||||
TextStyle? iconStyle(WidgetTester tester, IconData icon) {
|
||||
|
@ -1589,7 +1589,7 @@ void main() {
|
||||
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('Content1')));
|
||||
await tester.pump(const Duration(milliseconds: 200)); // splash is well underway
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))as RenderBox;
|
||||
expect(box, paints..circle(x: 68.0, y: 24.0, color: pressedColor));
|
||||
await gesture.up();
|
||||
});
|
||||
|
@ -1011,7 +1011,7 @@ void main() {
|
||||
await tester.tap(find.byKey(buttonKey));
|
||||
await tester.pump();
|
||||
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
// Make sure there is no overscroll
|
||||
expect(scrollController.offset, scrollController.position.maxScrollExtent);
|
||||
|
||||
@ -1854,7 +1854,7 @@ void main() {
|
||||
|
||||
double getMenuScroll() {
|
||||
double scrollPosition;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
assert(scrollController != null);
|
||||
scrollPosition = scrollController.position.pixels;
|
||||
assert(scrollPosition != null);
|
||||
@ -1890,7 +1890,7 @@ void main() {
|
||||
|
||||
double getMenuScroll() {
|
||||
double scrollPosition;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
assert(scrollController != null);
|
||||
scrollPosition = scrollController.position.pixels;
|
||||
assert(scrollPosition != null);
|
||||
@ -1927,7 +1927,7 @@ void main() {
|
||||
|
||||
double getMenuScroll() {
|
||||
double scrollPosition;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
assert(scrollController != null);
|
||||
scrollPosition = scrollController.position.pixels;
|
||||
assert(scrollPosition != null);
|
||||
@ -1964,7 +1964,7 @@ void main() {
|
||||
|
||||
double getMenuScroll() {
|
||||
double scrollPosition;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
final ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
assert(scrollController != null);
|
||||
scrollPosition = scrollController.position.pixels;
|
||||
assert(scrollPosition != null);
|
||||
@ -3066,7 +3066,7 @@ void main() {
|
||||
await tester.tap(find.text('0'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
ScrollController scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
// The scrollbar shouldn't show if the list fits into the screen.
|
||||
expect(scrollController.position.maxScrollExtent, 0);
|
||||
expect(find.byType(Scrollbar), isNot(paints..rect()));
|
||||
@ -3082,7 +3082,7 @@ void main() {
|
||||
await tester.tap(find.text('0'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)))!;
|
||||
scrollController = PrimaryScrollController.of(tester.element(find.byType(ListView)));
|
||||
// The scrollbar is shown when the list is longer than the height of the screen.
|
||||
expect(scrollController.position.maxScrollExtent > 0, isTrue);
|
||||
expect(find.byType(Scrollbar), paints..rect());
|
||||
|
@ -1279,7 +1279,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: NoSplash.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
await gesture.up();
|
||||
@ -1290,7 +1290,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
await gesture.up();
|
||||
|
@ -1307,7 +1307,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: NoSplash.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
await gesture.up();
|
||||
@ -1318,7 +1318,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
await gesture.up();
|
||||
|
@ -75,7 +75,7 @@ void main() {
|
||||
await tester.pump(); // start gesture
|
||||
await tester.pump(const Duration(milliseconds: 200)); // wait for splash to be well under way
|
||||
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
expect(
|
||||
box,
|
||||
paints
|
||||
@ -127,7 +127,7 @@ void main() {
|
||||
await tester.tapAt(tapDownOffset);
|
||||
await tester.pump(); // start gesture
|
||||
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))as RenderBox;
|
||||
|
||||
bool offsetsAreClose(Offset a, Offset b) => (a - b).distance < 1.0;
|
||||
bool radiiAreClose(double a, double b) => (a - b).abs() < 1.0;
|
||||
@ -205,7 +205,7 @@ void main() {
|
||||
await tester.pump(); // start gesture
|
||||
await tester.pump(const Duration(milliseconds: 200)); // wait for splash to be well under way
|
||||
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))as RenderBox;
|
||||
expect(
|
||||
box,
|
||||
paints
|
||||
@ -337,7 +337,7 @@ void main() {
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.space);
|
||||
await tester.pump();
|
||||
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))as RenderBox;
|
||||
|
||||
// ripplePattern always add a translation of topLeft.
|
||||
expect(box, ripplePattern(30.0, 0));
|
||||
@ -433,7 +433,7 @@ void main() {
|
||||
await gesture.moveTo(Offset.zero);
|
||||
await gesture.up(); // generates a tap cancel
|
||||
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))as RenderBox;
|
||||
expect(box, paints..everything((Symbol method, List<dynamic> arguments) {
|
||||
if (method != #drawCircle) {
|
||||
return true;
|
||||
|
@ -50,7 +50,7 @@ void main() {
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(buttonFinder))!;
|
||||
final MaterialInkController material = Material.of(tester.element(buttonFinder));
|
||||
expect(material, paintsExactlyCountTimes(#drawRect, 1));
|
||||
|
||||
// ignore: avoid_dynamic_calls
|
||||
@ -81,7 +81,7 @@ void main() {
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(buttonFinder))!;
|
||||
final MaterialInkController material = Material.of(tester.element(buttonFinder));
|
||||
expect(material, paintsExactlyCountTimes(#drawPaint, 1));
|
||||
},
|
||||
skip: kIsWeb, // [intended] shaders are not yet supported for web.
|
||||
|
@ -48,7 +48,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: NoSplash.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
await gesture.up();
|
||||
@ -59,7 +59,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame());
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
await gesture.up();
|
||||
|
@ -865,7 +865,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)));
|
||||
|
||||
// Press
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byKey(innerKey)), pointer: 1);
|
||||
@ -938,7 +938,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)));
|
||||
|
||||
// Press
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byKey(innerKey)), pointer: 1);
|
||||
@ -1019,7 +1019,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)));
|
||||
|
||||
// Press middle
|
||||
await tester.startGesture(tester.getTopLeft(find.byKey(middleKey)) + const Offset(1, 1), pointer: 1);
|
||||
@ -1079,7 +1079,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(leftKey)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(leftKey)));
|
||||
|
||||
final Offset parentPosition = tester.getTopLeft(find.byKey(parentKey)) + const Offset(1, 1);
|
||||
|
||||
@ -1191,7 +1191,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)));
|
||||
|
||||
// Press inner
|
||||
final TestGesture gesture = await tester.startGesture(const Offset(100, 50), pointer: 1);
|
||||
@ -1265,7 +1265,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byKey(innerKey)));
|
||||
|
||||
// Press
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byKey(innerKey)), pointer: 1);
|
||||
|
@ -1006,7 +1006,7 @@ void main() {
|
||||
child: SizedBox(key: sizedBoxKey, width: 20, height: 20),
|
||||
),
|
||||
));
|
||||
final MaterialInkController controller = Material.of(sizedBoxKey.currentContext!)!;
|
||||
final MaterialInkController controller = Material.of(sizedBoxKey.currentContext!);
|
||||
|
||||
final TrackPaintInkFeature tracker = TrackPaintInkFeature(
|
||||
controller: controller,
|
||||
@ -1015,7 +1015,7 @@ void main() {
|
||||
controller.addInkFeature(tracker);
|
||||
expect(tracker.paintCount, 0);
|
||||
|
||||
// Force a repaint. Since it's offstage, the ink feture should not get painted.
|
||||
// Force a repaint. Since it's offstage, the ink feature should not get painted.
|
||||
materialKey.currentContext!.findRenderObject()!.paint(PaintingContext(ContainerLayer(), Rect.largest), Offset.zero);
|
||||
expect(tracker.paintCount, 0);
|
||||
|
||||
|
@ -1442,7 +1442,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: NoSplash.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
await gesture.up();
|
||||
@ -1453,7 +1453,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
await gesture.up();
|
||||
|
@ -32,7 +32,7 @@ void main() {
|
||||
await tester.tap(find.text('BUTTON'));
|
||||
await tester.pump(const Duration(milliseconds: 10));
|
||||
|
||||
final RenderBox splash = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox splash = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
expect(splash, paints..circle(color: splashColor));
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
@ -72,7 +72,7 @@ void main() {
|
||||
await tester.pump(const Duration(milliseconds: 10));
|
||||
|
||||
if (!kIsWeb) {
|
||||
final RenderBox splash = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox splash = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
expect(splash, paints..circle(color: splashColor));
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ void main() {
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.space);
|
||||
await tester.pump(const Duration(milliseconds: 10));
|
||||
|
||||
final RenderBox splash = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox splash = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
expect(splash, paints..circle(color: splashColor));
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
@ -195,7 +195,7 @@ void main() {
|
||||
await tester.pump(); // start gesture
|
||||
await tester.pump(const Duration(milliseconds: 200)); // wait for splash to be well under way
|
||||
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
// centered in material button.
|
||||
expect(box, paints..circle(x: 44.0, y: 18.0, color: splashColor));
|
||||
await gesture.up();
|
||||
@ -226,7 +226,7 @@ void main() {
|
||||
final TestGesture gesture = await tester.startGesture(top);
|
||||
await tester.pump(); // start gesture
|
||||
await tester.pump(const Duration(milliseconds: 200)); // wait for splash to be well under way
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
// paints above material
|
||||
expect(box, paints..circle(x: 44.0, y: 0.0, color: splashColor));
|
||||
await gesture.up();
|
||||
@ -326,7 +326,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
expect(box, isNot(paints..rect(color: focusColor)));
|
||||
|
||||
focusNode.requestFocus();
|
||||
@ -425,7 +425,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell)))! as RenderBox;
|
||||
final RenderBox box = Material.of(tester.element(find.byType(InkWell))) as RenderBox;
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||
await gesture.addPointer();
|
||||
expect(box, isNot(paints..rect(color: hoverColor)));
|
||||
|
@ -1000,7 +1000,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// 5 tick marks and a thumb.
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 6));
|
||||
@ -1056,7 +1056,7 @@ void main() {
|
||||
}
|
||||
|
||||
Future<void> testReparenting(bool reparent) async {
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
final Offset center = tester.getCenter(find.byType(Slider));
|
||||
// Move to 0.0.
|
||||
TestGesture gesture = await tester.startGesture(Offset.zero);
|
||||
@ -2030,7 +2030,7 @@ void main() {
|
||||
await tester.pumpWidget(buildApp());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
// Check that thumb color is using active color.
|
||||
expect(material, paints..circle(color: activeColor));
|
||||
|
||||
@ -2989,7 +2989,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final MaterialInkController material =
|
||||
Material.of(tester.element(find.byType(Slider)))!;
|
||||
Material.of(tester.element(find.byType(Slider)));
|
||||
expect(material, paints..circle(color: color));
|
||||
});
|
||||
|
||||
@ -3012,7 +3012,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final MaterialInkController material =
|
||||
Material.of(tester.element(find.byType(Slider)))!;
|
||||
Material.of(tester.element(find.byType(Slider)));
|
||||
expect(material, paints..circle(color: color));
|
||||
});
|
||||
|
||||
@ -3032,7 +3032,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final MaterialInkController material =
|
||||
Material.of(tester.element(find.byType(CupertinoSlider)))!;
|
||||
Material.of(tester.element(find.byType(CupertinoSlider)));
|
||||
expect(
|
||||
material,
|
||||
paints
|
||||
@ -3064,7 +3064,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final MaterialInkController material =
|
||||
Material.of(tester.element(find.byType(CupertinoSlider)))!;
|
||||
Material.of(tester.element(find.byType(CupertinoSlider)));
|
||||
expect(
|
||||
material,
|
||||
paints..rrect()..rrect()..rrect()..rrect()..rrect()..rrect(color: color),
|
||||
|
@ -163,7 +163,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(buildApp());
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
|
||||
|
||||
// Check default theme for enabled widget.
|
||||
@ -356,7 +356,7 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, secondaryTrackValue: 0.75, enabled: false));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(
|
||||
material,
|
||||
@ -380,7 +380,7 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, secondaryTrackValue: 0.75, enabled: false));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(
|
||||
material,
|
||||
@ -487,7 +487,7 @@ void main() {
|
||||
final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, secondaryTrackValue: 0.5));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
const Radius radius = Radius.circular(2);
|
||||
const Radius activatedRadius = Radius.circular(3);
|
||||
@ -523,7 +523,7 @@ void main() {
|
||||
final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// With no touch, paints only the thumb.
|
||||
expect(
|
||||
@ -643,7 +643,7 @@ void main() {
|
||||
final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.45));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(material, paints..circle(color: sliderTheme.thumbColor, radius: 10.0));
|
||||
|
||||
@ -1050,7 +1050,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Top and bottom are centerY (300) + and - trackRadius (8).
|
||||
expect(
|
||||
@ -1082,7 +1082,7 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(
|
||||
material,
|
||||
@ -1106,7 +1106,7 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25));
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(
|
||||
material,
|
||||
@ -1132,7 +1132,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, divisions: 2));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(
|
||||
material,
|
||||
@ -1168,7 +1168,7 @@ void main() {
|
||||
await tester.startGesture(center);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
expect(
|
||||
material,
|
||||
paints..circle(
|
||||
@ -1190,7 +1190,7 @@ void main() {
|
||||
|
||||
final MaterialInkController material = Material.of(
|
||||
tester.element(find.byType(Slider)),
|
||||
)!;
|
||||
);
|
||||
|
||||
// The track rectangle begins at 10 pixels from the left of the screen and ends 10 pixels from the right
|
||||
// (790 pixels from the left). The main check here it that the track itself should be centered on
|
||||
@ -1242,7 +1242,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
expect(material, paintsExactlyCountTimes(#drawRect, 0));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
@ -1262,7 +1262,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Only 2 track segments.
|
||||
expect(material, paintsExactlyCountTimes(#drawRRect, 2));
|
||||
@ -1286,7 +1286,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Only 5 tick marks.
|
||||
expect(material, paintsExactlyCountTimes(#drawRect, 0));
|
||||
@ -1309,7 +1309,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Only 1 thumb.
|
||||
expect(material, paintsExactlyCountTimes(#drawRect, 0));
|
||||
@ -1333,7 +1333,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
|
||||
// Tap the center of the track and wait for animations to finish.
|
||||
final Offset center = tester.getCenter(find.byType(Slider));
|
||||
@ -1362,7 +1362,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
|
||||
|
||||
// Tap the center of the track and wait for animations to finish.
|
||||
@ -1393,7 +1393,7 @@ void main() {
|
||||
divisions: 4,
|
||||
));
|
||||
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.byType(Slider)));
|
||||
final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay));
|
||||
|
||||
// Tap the center of the track to kick off the animation of the value indicator.
|
||||
|
@ -364,7 +364,7 @@ void main() {
|
||||
expect(find.text('A'), findsOneWidget);
|
||||
expect(find.text('B'), findsOneWidget);
|
||||
expect(find.text('C'), findsOneWidget);
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')));
|
||||
expect(controller, isNotNull);
|
||||
expect(controller.index, 2);
|
||||
expect(controller.previousIndex, 2);
|
||||
@ -400,7 +400,7 @@ void main() {
|
||||
expect(find.text('A'), findsOneWidget);
|
||||
expect(find.text('B'), findsOneWidget);
|
||||
expect(find.text('C'), findsOneWidget);
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')));
|
||||
expect(controller.index, 2);
|
||||
expect(controller.previousIndex, 2);
|
||||
|
||||
@ -421,7 +421,7 @@ void main() {
|
||||
final List<String> tabs = <String>['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL'];
|
||||
const Key tabBarKey = Key('TabBar');
|
||||
await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')));
|
||||
expect(controller, isNotNull);
|
||||
expect(controller.index, 0);
|
||||
|
||||
@ -442,7 +442,7 @@ void main() {
|
||||
const Key tabBarKey = Key('TabBar');
|
||||
const EdgeInsetsGeometry padding = EdgeInsets.only(right: 30, left: 60);
|
||||
await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey, padding: padding));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')));
|
||||
expect(controller, isNotNull);
|
||||
expect(controller.index, 0);
|
||||
|
||||
@ -470,7 +470,7 @@ void main() {
|
||||
padding: padding,
|
||||
textDirection: TextDirection.rtl,
|
||||
));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')));
|
||||
expect(controller, isNotNull);
|
||||
expect(controller.index, 0);
|
||||
|
||||
@ -489,7 +489,7 @@ void main() {
|
||||
final List<String> tabs = <String>['AAAA', 'BBBB', 'CCCC', 'DDDD', 'EEEE', 'FFFF', 'GGGG', 'HHHH', 'IIII', 'JJJJ', 'KKKK', 'LLLL'];
|
||||
const Key tabBarKey = Key('TabBar');
|
||||
await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAA', isScrollable: true, tabBarKey: tabBarKey));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAA')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAA')));
|
||||
expect(controller, isNotNull);
|
||||
expect(controller.index, 0);
|
||||
|
||||
@ -529,7 +529,7 @@ void main() {
|
||||
}
|
||||
|
||||
await tester.pumpWidget(builder());
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA')));
|
||||
|
||||
TestGesture gesture = await tester.startGesture(tester.getCenter(find.text(tabs[0])));
|
||||
await gesture.moveBy(const Offset(-600.0, 0.0));
|
||||
@ -586,7 +586,7 @@ void main() {
|
||||
expect(find.text('LEFT CHILD'), findsOneWidget);
|
||||
expect(find.text('RIGHT CHILD'), findsNothing);
|
||||
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')));
|
||||
expect(controller.index, 0);
|
||||
|
||||
// Fling to the left, switch from the 'LEFT' tab to the 'RIGHT'
|
||||
@ -615,7 +615,7 @@ void main() {
|
||||
expect(find.text('LEFT CHILD'), findsOneWidget);
|
||||
expect(find.text('RIGHT CHILD'), findsNothing);
|
||||
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')));
|
||||
expect(controller.index, 0);
|
||||
|
||||
final Offset flingStart = tester.getCenter(find.text('LEFT CHILD'));
|
||||
@ -636,7 +636,7 @@ void main() {
|
||||
expect(find.text('LEFT CHILD'), findsOneWidget);
|
||||
expect(find.text('RIGHT CHILD'), findsNothing);
|
||||
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')));
|
||||
expect(controller.index, 0);
|
||||
|
||||
final Offset flingStart = tester.getCenter(find.text('LEFT CHILD'));
|
||||
@ -659,7 +659,7 @@ void main() {
|
||||
expect(find.text('LEFT CHILD'), findsOneWidget);
|
||||
expect(find.text('RIGHT CHILD'), findsNothing);
|
||||
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')));
|
||||
expect(controller.index, 0);
|
||||
|
||||
final Offset flingStart = tester.getCenter(find.text('LEFT CHILD'));
|
||||
@ -772,7 +772,7 @@ void main() {
|
||||
final List<String> tabs = <String>['LEFT', 'RIGHT'];
|
||||
|
||||
await tester.pumpWidget(buildLeftRightApp(tabs: tabs, value: 'LEFT'));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('LEFT')));
|
||||
|
||||
expect(controller, isNotNull);
|
||||
expect(controller.index, 0);
|
||||
@ -1013,7 +1013,7 @@ void main() {
|
||||
final List<String> tabs = <String>['A', 'B', 'C'];
|
||||
|
||||
await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', animationDuration: animationDuration));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')));
|
||||
|
||||
await tester.tap(find.text('A'));
|
||||
await tester.pump();
|
||||
@ -1241,7 +1241,7 @@ void main() {
|
||||
final List<String> tabs = <String>['A', 'B', 'C'];
|
||||
|
||||
await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', animationDuration: Duration.zero));
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
final TabController controller = DefaultTabController.of(tester.element(find.text('A')));
|
||||
|
||||
await tester.tap(find.text('A'));
|
||||
await tester.pump();
|
||||
@ -1288,7 +1288,7 @@ void main() {
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildWithTabBarView());
|
||||
TabController controller = DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
TabController controller = DefaultTabController.of(tester.element(find.text('A')));
|
||||
expect(controller.index, 0);
|
||||
|
||||
tabs.add('B');
|
||||
@ -1297,7 +1297,7 @@ void main() {
|
||||
await tester.pumpWidget(buildWithTabBarView());
|
||||
await tester.tap(find.text('C'));
|
||||
await tester.pumpAndSettle();
|
||||
controller = DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
controller = DefaultTabController.of(tester.element(find.text('A')));
|
||||
expect(controller.index, 2);
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
@ -3752,7 +3752,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
}
|
||||
TabController getController() => DefaultTabController.of(tester.element(find.text('A')))!;
|
||||
TabController getController() => DefaultTabController.of(tester.element(find.text('A')));
|
||||
|
||||
await tester.pumpWidget(buildTabs(threeTabs));
|
||||
await tester.tap(find.text('B'));
|
||||
@ -4346,7 +4346,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
|
||||
TabController getController() => DefaultTabController.of(tester.element(find.text('B')))!;
|
||||
TabController getController() => DefaultTabController.of(tester.element(find.text('B')));
|
||||
TabController controller = getController();
|
||||
|
||||
controller.animateTo(2, duration: const Duration(milliseconds: 200), curve: Curves.linear);
|
||||
|
@ -1249,7 +1249,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: NoSplash.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
||||
await gesture.up();
|
||||
@ -1260,7 +1260,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory));
|
||||
{
|
||||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')))!;
|
||||
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(material, paintsExactlyCountTimes(#drawCircle, 1));
|
||||
await gesture.up();
|
||||
|
@ -116,7 +116,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(Builder(
|
||||
builder: (BuildContext context) {
|
||||
textHeightBehavior = DefaultTextHeightBehavior.of(context);
|
||||
textHeightBehavior = DefaultTextHeightBehavior.maybeOf(context);
|
||||
return textWidget;
|
||||
},
|
||||
));
|
||||
|
@ -286,8 +286,8 @@ class _TestState extends State<Test> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_beforeController.setParent(PrimaryScrollController.of(context));
|
||||
_afterController.setParent(PrimaryScrollController.of(context));
|
||||
_beforeController.setParent(PrimaryScrollController.maybeOf(context));
|
||||
_afterController.setParent(PrimaryScrollController.maybeOf(context));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -215,7 +215,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame());
|
||||
expect(find.text('top'), findsOneWidget);
|
||||
|
||||
final ScrollPosition position = Scrollable.of(tester.element(find.text('middle')))!.position;
|
||||
final ScrollPosition position = Scrollable.of(tester.element(find.text('middle'))).position;
|
||||
expect(position.viewportDimension, 600.0);
|
||||
expect(position.pixels, 0.0);
|
||||
|
||||
|
@ -16,7 +16,7 @@ void main() {
|
||||
home: StatefulBuilder(
|
||||
key: builderKey,
|
||||
builder: (BuildContext context, StateSetter setter) {
|
||||
PageStorage.of(context)!.writeState(context, storedValue);
|
||||
PageStorage.of(context).writeState(context, storedValue);
|
||||
setState = setter;
|
||||
return Center(
|
||||
child: Text('storedValue: $storedValue'),
|
||||
@ -28,13 +28,13 @@ void main() {
|
||||
|
||||
final Element builderElement = tester.element(find.byKey(builderKey));
|
||||
expect(PageStorage.of(builderElement), isNotNull);
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement), equals(storedValue));
|
||||
expect(PageStorage.of(builderElement).readState(builderElement), equals(storedValue));
|
||||
|
||||
setState(() {
|
||||
storedValue = 1;
|
||||
});
|
||||
await tester.pump();
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement), equals(storedValue));
|
||||
expect(PageStorage.of(builderElement).readState(builderElement), equals(storedValue));
|
||||
});
|
||||
|
||||
testWidgets('PageStorage read and write by identifier', (WidgetTester tester) async {
|
||||
@ -46,7 +46,7 @@ void main() {
|
||||
home: StatefulBuilder(
|
||||
key: key,
|
||||
builder: (BuildContext context, StateSetter setter) {
|
||||
PageStorage.of(context)!.writeState(context, storedValue, identifier: 123);
|
||||
PageStorage.of(context).writeState(context, storedValue, identifier: 123);
|
||||
setState = setter;
|
||||
return Center(
|
||||
child: Text('storedValue: $storedValue'),
|
||||
@ -60,8 +60,8 @@ void main() {
|
||||
await tester.pumpWidget(buildWidthKey(key));
|
||||
Element builderElement = tester.element(find.byKey(key));
|
||||
expect(PageStorage.of(builderElement), isNotNull);
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement), isNull);
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement, identifier: 123), equals(storedValue));
|
||||
expect(PageStorage.of(builderElement).readState(builderElement), isNull);
|
||||
expect(PageStorage.of(builderElement).readState(builderElement, identifier: 123), equals(storedValue));
|
||||
|
||||
// New StatefulBuilder widget - different key - but the same PageStorage identifier.
|
||||
|
||||
@ -69,14 +69,14 @@ void main() {
|
||||
await tester.pumpWidget(buildWidthKey(key));
|
||||
builderElement = tester.element(find.byKey(key));
|
||||
expect(PageStorage.of(builderElement), isNotNull);
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement), isNull);
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement, identifier: 123), equals(storedValue));
|
||||
expect(PageStorage.of(builderElement).readState(builderElement), isNull);
|
||||
expect(PageStorage.of(builderElement).readState(builderElement, identifier: 123), equals(storedValue));
|
||||
|
||||
setState(() {
|
||||
storedValue = 1;
|
||||
});
|
||||
await tester.pump();
|
||||
expect(PageStorage.of(builderElement)!.readState(builderElement, identifier: 123), equals(storedValue));
|
||||
expect(PageStorage.of(builderElement).readState(builderElement, identifier: 123), equals(storedValue));
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ class BucketSpyState extends State<BucketSpy> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
bucket = RestorationScope.of(context);
|
||||
bucket = RestorationScope.maybeOf(context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -22,11 +22,11 @@ void main() {
|
||||
});
|
||||
|
||||
T findPhysics<T extends ScrollPhysics>(WidgetTester tester) {
|
||||
return Scrollable.of(find.byType(TestWidget).evaluate().first)!.position.physics as T;
|
||||
return Scrollable.of(find.byType(TestWidget).evaluate().first).position.physics as T;
|
||||
}
|
||||
|
||||
ScrollMetrics findMetrics(WidgetTester tester) {
|
||||
return Scrollable.of(find.byType(TestWidget).evaluate().first)!.position;
|
||||
return Scrollable.of(find.byType(TestWidget).evaluate().first).position;
|
||||
}
|
||||
|
||||
testWidgets('ScrollAwareImageProvider does not delay if widget is not in scrollable', (WidgetTester tester) async {
|
||||
|
@ -50,7 +50,7 @@ void main() {
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
behavior = ScrollConfiguration.of(context) as TestScrollBehavior;
|
||||
position = Scrollable.of(context)!.position as ScrollPositionWithSingleContext;
|
||||
position = Scrollable.of(context).position as ScrollPositionWithSingleContext;
|
||||
return Container(height: 1000.0);
|
||||
},
|
||||
),
|
||||
|
@ -218,7 +218,7 @@ void main() {
|
||||
ScrollNotificationObserver(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
observer = ScrollNotificationObserver.of(context)!;
|
||||
observer = ScrollNotificationObserver.of(context);
|
||||
return const SingleChildScrollView(
|
||||
child: SizedBox(height: 1200.0),
|
||||
);
|
||||
|
@ -1478,7 +1478,7 @@ void main() {
|
||||
);
|
||||
final ScrollController controller = PrimaryScrollController.of(
|
||||
tester.element(find.byType(CustomScrollView)),
|
||||
)!;
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(controller.position.pixels, equals(0.0));
|
||||
expect(
|
||||
|
@ -22,7 +22,7 @@ class _ScrollPositionListenerState extends State<ScrollPositionListener> {
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_position?.removeListener(listener);
|
||||
_position = Scrollable.of(context)?.position;
|
||||
_position = Scrollable.maybeOf(context)?.position;
|
||||
_position?.addListener(listener);
|
||||
widget.log('didChangeDependencies ${_position?.pixels.toStringAsFixed(1)}');
|
||||
}
|
||||
|
@ -941,7 +941,7 @@ void main() {
|
||||
// Getting the tester to simulate a life-like fling is difficult.
|
||||
// Instead, just manually drive the activity with a ballistic simulation as
|
||||
// if the user has flung the list.
|
||||
Scrollable.of(find.byType(SizedBox).evaluate().first)!.position.activity!.delegate.goBallistic(4000);
|
||||
Scrollable.of(find.byType(SizedBox).evaluate().first).position.activity!.delegate.goBallistic(4000);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const ValueKey<String>('Box 0')), findsNothing);
|
||||
@ -970,7 +970,7 @@ void main() {
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final ScrollPosition position = Scrollable.of(find.byType(SizedBox).evaluate().first)!.position;
|
||||
final ScrollPosition position = Scrollable.of(find.byType(SizedBox).evaluate().first).position;
|
||||
final SuperPessimisticScrollPhysics physics = position.physics as SuperPessimisticScrollPhysics;
|
||||
|
||||
expect(find.byKey(const ValueKey<String>('Box 0')), findsOneWidget);
|
||||
@ -1014,7 +1014,7 @@ void main() {
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final ScrollPosition position = Scrollable.of(find.byType(SizedBox).evaluate().first)!.position;
|
||||
final ScrollPosition position = Scrollable.of(find.byType(SizedBox).evaluate().first).position;
|
||||
|
||||
expect(find.byKey(const ValueKey<String>('Cheap box 0')), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey<String>('Cheap box 52')), findsNothing);
|
||||
|
@ -1028,7 +1028,7 @@ void main() {
|
||||
);
|
||||
final ScrollController controller = PrimaryScrollController.of(
|
||||
tester.element(find.byType(ListView)),
|
||||
)!;
|
||||
);
|
||||
expect(controller.position.pixels, 0.0);
|
||||
expect(value, isTrue);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user