Add maybeOf for all the cases where of returns nullable. (#114120)

This commit is contained in:
Greg Spencer 2022-10-31 16:09:09 -07:00 committed by GitHub
parent b20b7d995b
commit 37b72342b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 836 additions and 308 deletions

View File

@ -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; },

View File

@ -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,

View File

@ -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;
}

View File

@ -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]);
},
);
},

View File

@ -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;
});
}

View File

@ -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'),

View File

@ -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.

View File

@ -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) {

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -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,
);

View File

@ -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;

View File

@ -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();

View File

@ -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) {

View File

@ -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();
}

View File

@ -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,

View File

@ -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

View File

@ -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) {

View File

@ -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].
///

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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

View File

@ -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();
}

View File

@ -1088,7 +1088,7 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
void updateParent() {
_outerPosition?.setParent(
_parent ?? PrimaryScrollController.of(_state.context),
_parent ?? PrimaryScrollController.maybeOf(_state.context),
);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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(

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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(

View File

@ -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');

View File

@ -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;
}

View File

@ -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(

View File

@ -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);
}

View File

@ -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(

View File

@ -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;

View File

@ -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) {

View File

@ -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();
});

View File

@ -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());

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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.

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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)));

View File

@ -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),

View File

@ -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.

View File

@ -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);

View File

@ -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();

View File

@ -116,7 +116,7 @@ void main() {
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
textHeightBehavior = DefaultTextHeightBehavior.of(context);
textHeightBehavior = DefaultTextHeightBehavior.maybeOf(context);
return textWidget;
},
));

View File

@ -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

View File

@ -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);

View File

@ -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));
});
}

View File

@ -21,7 +21,7 @@ class BucketSpyState extends State<BucketSpy> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
bucket = RestorationScope.of(context);
bucket = RestorationScope.maybeOf(context);
}
@override

View File

@ -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 {

View File

@ -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);
},
),

View File

@ -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),
);

View File

@ -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(

View File

@ -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)}');
}

View File

@ -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);

View File

@ -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);