Minor fix compendium (#107874)
This commit is contained in:
parent
da88c953c7
commit
9b2668a451
@ -4,4 +4,4 @@ The [snippets] tool uses the files in the `skeletons` directory to inject code
|
|||||||
blocks generated from `{@tool dartpad}`, `{@tool sample}`, and `{@tool snippet}`
|
blocks generated from `{@tool dartpad}`, `{@tool sample}`, and `{@tool snippet}`
|
||||||
sections found in doc comments into the API docs.
|
sections found in doc comments into the API docs.
|
||||||
|
|
||||||
[snippet]: https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets
|
[snippets]: https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets
|
||||||
|
@ -30,6 +30,10 @@ that on an Android device like so:
|
|||||||
|
|
||||||
## Naming
|
## Naming
|
||||||
|
|
||||||
|
> `lib/library/file/class_name.n.dart`
|
||||||
|
>
|
||||||
|
> `lib/library/file/class_name.member_name.n.dart`
|
||||||
|
|
||||||
The naming scheme for the files is similar to the hierarchy under
|
The naming scheme for the files is similar to the hierarchy under
|
||||||
[packages/flutter/lib/src](../../packages/flutter/lib/src), except that the
|
[packages/flutter/lib/src](../../packages/flutter/lib/src), except that the
|
||||||
files are represented as directories (without the `.dart` suffix), and each
|
files are represented as directories (without the `.dart` suffix), and each
|
||||||
|
26
examples/api/lib/widgets/app/widgets_app.widgets_app.0.dart
Normal file
26
examples/api/lib/widgets/app/widgets_app.widgets_app.0.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flutter code sample for WidgetsApp
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
void main() => runApp(const MyApp());
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return WidgetsApp(
|
||||||
|
title: 'Example',
|
||||||
|
color: const Color(0xFF000000),
|
||||||
|
home: const Center(child: Text('Hello World')),
|
||||||
|
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) => PageRouteBuilder<T>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => builder(context),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter_api_samples/widgets/app/widgets_app.widgets_app.0.dart' as example;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('WidgetsApp test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.MyApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.text('Hello World'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
@ -19,6 +19,10 @@ import 'localizations.dart';
|
|||||||
/// assert(debugCheckHasCupertinoLocalizations(context));
|
/// assert(debugCheckHasCupertinoLocalizations(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
bool debugCheckHasCupertinoLocalizations(BuildContext context) {
|
bool debugCheckHasCupertinoLocalizations(BuildContext context) {
|
||||||
assert(() {
|
assert(() {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ValueListenable, clampDouble;
|
import 'package:flutter/foundation.dart' show ValueListenable, clampDouble;
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'button.dart';
|
import 'button.dart';
|
||||||
@ -32,8 +31,11 @@ const CupertinoDynamicColor _kToolbarBackgroundColor = CupertinoDynamicColor.wit
|
|||||||
darkColor: Color(0xff302928),
|
darkColor: Color(0xff302928),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Desktop Cupertino styled text selection controls.
|
||||||
class _CupertinoDesktopTextSelectionControls extends TextSelectionControls {
|
///
|
||||||
|
/// The [cupertinoDesktopTextSelectionControls] global variable has a
|
||||||
|
/// suitable instance of this class.
|
||||||
|
class CupertinoDesktopTextSelectionControls extends TextSelectionControls {
|
||||||
/// Desktop has no text selection handles.
|
/// Desktop has no text selection handles.
|
||||||
@override
|
@override
|
||||||
Size getHandleSize(double textLineHeight) {
|
Size getHandleSize(double textLineHeight) {
|
||||||
@ -87,7 +89,7 @@ class _CupertinoDesktopTextSelectionControls extends TextSelectionControls {
|
|||||||
|
|
||||||
/// Text selection controls that follows Mac design conventions.
|
/// Text selection controls that follows Mac design conventions.
|
||||||
final TextSelectionControls cupertinoDesktopTextSelectionControls =
|
final TextSelectionControls cupertinoDesktopTextSelectionControls =
|
||||||
_CupertinoDesktopTextSelectionControls();
|
CupertinoDesktopTextSelectionControls();
|
||||||
|
|
||||||
// Generates the child that's passed into CupertinoDesktopTextSelectionToolbar.
|
// Generates the child that's passed into CupertinoDesktopTextSelectionToolbar.
|
||||||
class _CupertinoDesktopTextSelectionControlsToolbar extends StatefulWidget {
|
class _CupertinoDesktopTextSelectionControlsToolbar extends StatefulWidget {
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ValueListenable, clampDouble;
|
import 'package:flutter/foundation.dart' show ValueListenable, clampDouble;
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'localizations.dart';
|
import 'localizations.dart';
|
||||||
@ -192,6 +191,9 @@ class _TextSelectionHandlePainter extends CustomPainter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// iOS Cupertino styled text selection controls.
|
/// iOS Cupertino styled text selection controls.
|
||||||
|
///
|
||||||
|
/// The [cupertinoTextSelectionControls] global variable has a
|
||||||
|
/// suitable instance of this class.
|
||||||
class CupertinoTextSelectionControls extends TextSelectionControls {
|
class CupertinoTextSelectionControls extends TextSelectionControls {
|
||||||
/// Returns the size of the Cupertino handle.
|
/// Returns the size of the Cupertino handle.
|
||||||
@override
|
@override
|
||||||
|
@ -23,6 +23,10 @@ import 'scaffold.dart' show Scaffold, ScaffoldMessenger;
|
|||||||
/// assert(debugCheckHasMaterial(context));
|
/// assert(debugCheckHasMaterial(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// This method can be expensive (it walks the element tree).
|
/// This method can be expensive (it walks the element tree).
|
||||||
///
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
@ -67,6 +71,10 @@ bool debugCheckHasMaterial(BuildContext context) {
|
|||||||
/// assert(debugCheckHasMaterialLocalizations(context));
|
/// assert(debugCheckHasMaterialLocalizations(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// This function has the side-effect of establishing an inheritance
|
/// This function has the side-effect of establishing an inheritance
|
||||||
/// relationship with the nearest [Localizations] widget (see
|
/// relationship with the nearest [Localizations] widget (see
|
||||||
/// [BuildContext.dependOnInheritedWidgetOfExactType]). This is ok if the caller
|
/// [BuildContext.dependOnInheritedWidgetOfExactType]). This is ok if the caller
|
||||||
@ -112,6 +120,10 @@ bool debugCheckHasMaterialLocalizations(BuildContext context) {
|
|||||||
/// assert(debugCheckHasScaffold(context));
|
/// assert(debugCheckHasScaffold(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// This method can be expensive (it walks the element tree).
|
/// This method can be expensive (it walks the element tree).
|
||||||
///
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
@ -145,6 +157,10 @@ bool debugCheckHasScaffold(BuildContext context) {
|
|||||||
/// assert(debugCheckHasScaffoldMessenger(context));
|
/// assert(debugCheckHasScaffoldMessenger(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// This method can be expensive (it walks the element tree).
|
/// This method can be expensive (it walks the element tree).
|
||||||
///
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ValueListenable, clampDouble;
|
import 'package:flutter/foundation.dart' show ValueListenable, clampDouble;
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
@ -19,7 +18,11 @@ import 'theme.dart';
|
|||||||
const double _kToolbarScreenPadding = 8.0;
|
const double _kToolbarScreenPadding = 8.0;
|
||||||
const double _kToolbarWidth = 222.0;
|
const double _kToolbarWidth = 222.0;
|
||||||
|
|
||||||
class _DesktopTextSelectionControls extends TextSelectionControls {
|
/// Desktop Material styled text selection controls.
|
||||||
|
///
|
||||||
|
/// The [desktopTextSelectionControls] global variable has a
|
||||||
|
/// suitable instance of this class.
|
||||||
|
class DesktopTextSelectionControls extends TextSelectionControls {
|
||||||
/// Desktop has no text selection handles.
|
/// Desktop has no text selection handles.
|
||||||
@override
|
@override
|
||||||
Size getHandleSize(double textLineHeight) {
|
Size getHandleSize(double textLineHeight) {
|
||||||
@ -83,7 +86,7 @@ class _DesktopTextSelectionControls extends TextSelectionControls {
|
|||||||
|
|
||||||
/// Text selection controls that loosely follows Material design conventions.
|
/// Text selection controls that loosely follows Material design conventions.
|
||||||
final TextSelectionControls desktopTextSelectionControls =
|
final TextSelectionControls desktopTextSelectionControls =
|
||||||
_DesktopTextSelectionControls();
|
DesktopTextSelectionControls();
|
||||||
|
|
||||||
// Generates the child that's passed into DesktopTextSelectionToolbar.
|
// Generates the child that's passed into DesktopTextSelectionToolbar.
|
||||||
class _DesktopTextSelectionControlsToolbar extends StatefulWidget {
|
class _DesktopTextSelectionControlsToolbar extends StatefulWidget {
|
||||||
@ -145,12 +148,14 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
|
assert(debugCheckHasMediaQuery(context));
|
||||||
|
|
||||||
// Don't render the menu until the state of the clipboard is known.
|
// Don't render the menu until the state of the clipboard is known.
|
||||||
if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) {
|
if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) {
|
||||||
return const SizedBox(width: 0.0, height: 0.0);
|
return const SizedBox(width: 0.0, height: 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(debugCheckHasMediaQuery(context));
|
|
||||||
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
final Offset midpointAnchor = Offset(
|
final Offset midpointAnchor = Offset(
|
||||||
@ -161,7 +166,6 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect
|
|||||||
widget.selectionMidpoint.dy - widget.globalEditableRegion.top,
|
widget.selectionMidpoint.dy - widget.globalEditableRegion.top,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
|
||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
final List<Widget> items = <Widget>[];
|
final List<Widget> items = <Widget>[];
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
import 'debug.dart';
|
||||||
import 'desktop_text_selection.dart';
|
import 'desktop_text_selection.dart';
|
||||||
import 'magnifier.dart';
|
import 'magnifier.dart';
|
||||||
import 'text_selection.dart';
|
import 'text_selection.dart';
|
||||||
@ -19,6 +20,10 @@ import 'theme.dart';
|
|||||||
/// a specific screen, consider wrapping the body of the [Route] with a
|
/// a specific screen, consider wrapping the body of the [Route] with a
|
||||||
/// [SelectionArea].
|
/// [SelectionArea].
|
||||||
///
|
///
|
||||||
|
/// The [SelectionArea] widget must have a [Localizations] ancestor that
|
||||||
|
/// contains a [MaterialLocalizations] delegate; using the [MaterialApp] widget
|
||||||
|
/// ensures that such an ancestor is present.
|
||||||
|
///
|
||||||
/// {@tool dartpad}
|
/// {@tool dartpad}
|
||||||
/// This example shows how to make a screen selectable.
|
/// This example shows how to make a screen selectable.
|
||||||
///
|
///
|
||||||
@ -85,6 +90,7 @@ class _SelectionAreaState extends State<SelectionArea> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
TextSelectionControls? controls = widget.selectionControls;
|
TextSelectionControls? controls = widget.selectionControls;
|
||||||
switch (Theme.of(context).platform) {
|
switch (Theme.of(context).platform) {
|
||||||
case TargetPlatform.android:
|
case TargetPlatform.android:
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
@ -22,6 +21,9 @@ const double _kToolbarContentDistanceBelow = _kHandleSize - 2.0;
|
|||||||
const double _kToolbarContentDistance = 8.0;
|
const double _kToolbarContentDistance = 8.0;
|
||||||
|
|
||||||
/// Android Material styled text selection controls.
|
/// Android Material styled text selection controls.
|
||||||
|
///
|
||||||
|
/// The [materialTextSelectionControls] global variable has a
|
||||||
|
/// suitable instance of this class.
|
||||||
class MaterialTextSelectionControls extends TextSelectionControls {
|
class MaterialTextSelectionControls extends TextSelectionControls {
|
||||||
/// Returns the size of the Material handle.
|
/// Returns the size of the Material handle.
|
||||||
@override
|
@override
|
||||||
|
@ -420,6 +420,8 @@ class RenderParagraph extends RenderBox
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The color to use when painting the selection.
|
/// The color to use when painting the selection.
|
||||||
|
///
|
||||||
|
/// Ignored if the text is not selectable (e.g. if [registrar] is null).
|
||||||
Color? get selectionColor => _selectionColor;
|
Color? get selectionColor => _selectionColor;
|
||||||
Color? _selectionColor;
|
Color? _selectionColor;
|
||||||
set selectionColor(Color? value) {
|
set selectionColor(Color? value) {
|
||||||
|
@ -282,7 +282,7 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// If [home] or [routes] are not null, the routing implementation needs to know how
|
/// If [home] or [routes] are not null, the routing implementation needs to know how
|
||||||
/// appropriately build [PageRoute]s. This can be achieved by supplying the
|
/// appropriately build [PageRoute]s. This can be achieved by supplying the
|
||||||
/// [pageRouteBuilder] parameter. The [pageRouteBuilder] is used by [MaterialApp]
|
/// [pageRouteBuilder] parameter. The [pageRouteBuilder] is used by [MaterialApp]
|
||||||
/// and [CupertinoApp] to create [MaterialPageRoute]s and [CupertinoPageRoute],
|
/// and [CupertinoApp] to create [MaterialPageRoute]s and [CupertinoPageRoute],
|
||||||
/// respectively.
|
/// respectively.
|
||||||
///
|
///
|
||||||
@ -296,15 +296,21 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
/// and [builder] are null, or if they fail to create a requested route,
|
/// and [builder] are null, or if they fail to create a requested route,
|
||||||
/// [onGenerateRoute] will be invoked. If that fails, [onUnknownRoute] will be invoked.
|
/// [onGenerateRoute] will be invoked. If that fails, [onUnknownRoute] will be invoked.
|
||||||
///
|
///
|
||||||
/// The [pageRouteBuilder] will create a [PageRoute] that wraps newly built routes.
|
/// The [pageRouteBuilder] is called to create a [PageRoute] that wraps newly built routes.
|
||||||
/// If the [builder] is non-null and the [onGenerateRoute] argument is null, then the
|
/// If the [builder] is non-null and the [onGenerateRoute] argument is null, then the
|
||||||
/// [builder] will not be provided only with the context and the child widget, whereas
|
/// [builder] will be provided only with the context and the child widget, whereas
|
||||||
/// the [pageRouteBuilder] will be provided with [RouteSettings]. If [onGenerateRoute]
|
/// the [pageRouteBuilder] will be provided with [RouteSettings]; in that configuration,
|
||||||
/// is not provided, [navigatorKey], [onUnknownRoute], [navigatorObservers], and
|
/// the [navigatorKey], [onUnknownRoute], [navigatorObservers], and
|
||||||
/// [initialRoute] must have their default values, as they will have no effect.
|
/// [initialRoute] properties must have their default values, as they will have no effect.
|
||||||
///
|
///
|
||||||
/// The `supportedLocales` argument must be a list of one or more elements.
|
/// The `supportedLocales` argument must be a list of one or more elements.
|
||||||
/// By default supportedLocales is `[const Locale('en', 'US')]`.
|
/// By default supportedLocales is `[const Locale('en', 'US')]`.
|
||||||
|
///
|
||||||
|
/// {@tool dartpad}
|
||||||
|
/// This sample shows a basic Flutter application using [WidgetsApp].
|
||||||
|
///
|
||||||
|
/// ** See code in examples/api/lib/widgets/app/widgets_app.widgets_app.0.dart **
|
||||||
|
/// {@end-tool}
|
||||||
WidgetsApp({ // can't be const because the asserts use methods on Iterable :-(
|
WidgetsApp({ // can't be const because the asserts use methods on Iterable :-(
|
||||||
super.key,
|
super.key,
|
||||||
this.navigatorKey,
|
this.navigatorKey,
|
||||||
@ -530,8 +536,23 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
/// The [PageRoute] generator callback used when the app is navigated to a
|
/// The [PageRoute] generator callback used when the app is navigated to a
|
||||||
/// named route.
|
/// named route.
|
||||||
///
|
///
|
||||||
|
/// A [PageRoute] represents the page in a [Navigator], so that it can
|
||||||
|
/// correctly animate between pages, and to represent the "return value" of
|
||||||
|
/// a route (e.g. which button a user selected in a modal dialog).
|
||||||
|
///
|
||||||
/// This callback can be used, for example, to specify that a [MaterialPageRoute]
|
/// This callback can be used, for example, to specify that a [MaterialPageRoute]
|
||||||
/// or a [CupertinoPageRoute] should be used for building page transitions.
|
/// or a [CupertinoPageRoute] should be used for building page transitions.
|
||||||
|
///
|
||||||
|
/// The [PageRouteFactory] type is generic, meaning the provided function must
|
||||||
|
/// itself be generic. For example (with special emphasis on the `<T>` at the
|
||||||
|
/// start of the closure):
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) => PageRouteBuilder<T>(
|
||||||
|
/// settings: settings,
|
||||||
|
/// pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => builder(context),
|
||||||
|
/// ),
|
||||||
|
/// ```
|
||||||
final PageRouteFactory? pageRouteBuilder;
|
final PageRouteFactory? pageRouteBuilder;
|
||||||
|
|
||||||
/// {@template flutter.widgets.widgetsApp.routeInformationParser}
|
/// {@template flutter.widgets.widgetsApp.routeInformationParser}
|
||||||
|
@ -5657,9 +5657,17 @@ class RichText extends MultiChildRenderObjectWidget {
|
|||||||
final ui.TextHeightBehavior? textHeightBehavior;
|
final ui.TextHeightBehavior? textHeightBehavior;
|
||||||
|
|
||||||
/// The [SelectionRegistrar] this rich text is subscribed to.
|
/// The [SelectionRegistrar] this rich text is subscribed to.
|
||||||
|
///
|
||||||
|
/// If this is set, [selectionColor] must be non-null.
|
||||||
final SelectionRegistrar? selectionRegistrar;
|
final SelectionRegistrar? selectionRegistrar;
|
||||||
|
|
||||||
/// The color to use when painting the selection.
|
/// The color to use when painting the selection.
|
||||||
|
///
|
||||||
|
/// This is ignored if [selectionRegistrar] is null.
|
||||||
|
///
|
||||||
|
/// See the section on selections in the [RichText] top-level API
|
||||||
|
/// documentation for more details on enabling selection in [RichText]
|
||||||
|
/// widgets.
|
||||||
final Color? selectionColor;
|
final Color? selectionColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -252,6 +252,10 @@ bool debugItemsHaveDuplicateKeys(Iterable<Widget> items) {
|
|||||||
/// assert(debugCheckHasTable(context));
|
/// assert(debugCheckHasTable(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// This method can be expensive (it walks the element tree).
|
/// This method can be expensive (it walks the element tree).
|
||||||
///
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
@ -282,6 +286,10 @@ bool debugCheckHasTable(BuildContext context) {
|
|||||||
/// assert(debugCheckHasMediaQuery(context));
|
/// assert(debugCheckHasMediaQuery(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
bool debugCheckHasMediaQuery(BuildContext context) {
|
bool debugCheckHasMediaQuery(BuildContext context) {
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -334,6 +342,10 @@ bool debugCheckHasMediaQuery(BuildContext context) {
|
|||||||
/// If they are non-null, they are included in the order above, interspersed
|
/// If they are non-null, they are included in the order above, interspersed
|
||||||
/// with the more generic advice regarding [Directionality].
|
/// with the more generic advice regarding [Directionality].
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
bool debugCheckHasDirectionality(BuildContext context, { String? why, String? hint, String? alternative }) {
|
bool debugCheckHasDirectionality(BuildContext context, { String? why, String? hint, String? alternative }) {
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -406,6 +418,10 @@ void debugWidgetBuilderValue(Widget widget, Widget? built) {
|
|||||||
/// assert(debugCheckHasWidgetsLocalizations(context));
|
/// assert(debugCheckHasWidgetsLocalizations(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
bool debugCheckHasWidgetsLocalizations(BuildContext context) {
|
bool debugCheckHasWidgetsLocalizations(BuildContext context) {
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -443,6 +459,10 @@ bool debugCheckHasWidgetsLocalizations(BuildContext context) {
|
|||||||
/// assert(debugCheckHasOverlay(context));
|
/// assert(debugCheckHasOverlay(context));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Always place this before any early returns, so that the invariant is checked
|
||||||
|
/// in all cases. This prevents bugs from hiding until a particular codepath is
|
||||||
|
/// hit.
|
||||||
|
///
|
||||||
/// This method can be expensive (it walks the element tree).
|
/// This method can be expensive (it walks the element tree).
|
||||||
///
|
///
|
||||||
/// Does nothing if asserts are disabled. Always returns true.
|
/// Does nothing if asserts are disabled. Always returns true.
|
||||||
|
@ -31,7 +31,7 @@ class DefaultSelectionStyle extends InheritedTheme {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/// A const-constructable default selection style that provides fallback
|
/// A const-constructable default selection style that provides fallback
|
||||||
/// values.
|
/// values (null).
|
||||||
///
|
///
|
||||||
/// Returned from [of] when the given [BuildContext] doesn't have an enclosing
|
/// Returned from [of] when the given [BuildContext] doesn't have an enclosing
|
||||||
/// default selection style.
|
/// default selection style.
|
||||||
@ -43,6 +43,12 @@ class DefaultSelectionStyle extends InheritedTheme {
|
|||||||
selectionColor = null,
|
selectionColor = null,
|
||||||
super(child: const _NullWidget());
|
super(child: const _NullWidget());
|
||||||
|
|
||||||
|
/// The default cursor and selection color (semi-transparent grey).
|
||||||
|
///
|
||||||
|
/// This is the color that the [Text] widget uses when the specified selection
|
||||||
|
/// color is null.
|
||||||
|
static const Color defaultColor = Color(0x80808080);
|
||||||
|
|
||||||
/// The color of the text field's cursor.
|
/// The color of the text field's cursor.
|
||||||
///
|
///
|
||||||
/// The cursor indicates the current location of the text insertion point in
|
/// The cursor indicates the current location of the text insertion point in
|
||||||
@ -88,9 +94,9 @@ class _NullWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
throw FlutterError(
|
throw FlutterError(
|
||||||
'A DefaultTextStyle constructed with DefaultTextStyle.fallback cannot be incorporated into the widget tree, '
|
'A DefaultSelectionStyle constructed with DefaultSelectionStyle.fallback cannot be incorporated into the widget tree, '
|
||||||
'it is meant only to provide a fallback value returned by DefaultTextStyle.of() '
|
'it is meant only to provide a fallback value returned by DefaultSelectionStyle.of() '
|
||||||
'when no enclosing default text style is present in a BuildContext.',
|
'when no enclosing default selection style is present in a BuildContext.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -572,7 +572,7 @@ class EditableText extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// The [controller], [focusNode], [obscureText], [autocorrect], [autofocus],
|
/// The [controller], [focusNode], [obscureText], [autocorrect], [autofocus],
|
||||||
/// [showSelectionHandles], [enableInteractiveSelection], [forceLine],
|
/// [showSelectionHandles], [enableInteractiveSelection], [forceLine],
|
||||||
/// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor],
|
/// [style], [cursorColor], [cursorOpacityAnimates], [backgroundCursorColor],
|
||||||
/// [enableSuggestions], [paintCursorAboveText], [selectionHeightStyle],
|
/// [enableSuggestions], [paintCursorAboveText], [selectionHeightStyle],
|
||||||
/// [selectionWidthStyle], [textAlign], [dragStartBehavior], [scrollPadding],
|
/// [selectionWidthStyle], [textAlign], [dragStartBehavior], [scrollPadding],
|
||||||
/// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer],
|
/// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer],
|
||||||
|
@ -281,6 +281,10 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> {
|
|||||||
/// navigation and being able to insert widgets on top of the pages in an app.
|
/// navigation and being able to insert widgets on top of the pages in an app.
|
||||||
/// To simply display a stack of widgets, consider using [Stack] instead.
|
/// To simply display a stack of widgets, consider using [Stack] instead.
|
||||||
///
|
///
|
||||||
|
/// An [Overlay] widget requires a [Directionality] widget to be in scope, so
|
||||||
|
/// that it can resolve direction-sensitive coordinates of any
|
||||||
|
/// [Positioned.directional] children.
|
||||||
|
///
|
||||||
/// {@tool dartpad}
|
/// {@tool dartpad}
|
||||||
/// This example shows how to use the [Overlay] to highlight the [NavigationBar]
|
/// This example shows how to use the [Overlay] to highlight the [NavigationBar]
|
||||||
/// destination.
|
/// destination.
|
||||||
|
@ -7,6 +7,13 @@ import 'framework.dart';
|
|||||||
import 'routes.dart';
|
import 'routes.dart';
|
||||||
|
|
||||||
/// A modal route that replaces the entire screen.
|
/// A modal route that replaces the entire screen.
|
||||||
|
///
|
||||||
|
/// The [PageRouteBuilder] subclass provides a way to create a [PageRoute] using
|
||||||
|
/// callbacks rather than by defining a new class via subclassing.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Route], which documents the meaning of the `T` generic type argument.
|
||||||
abstract class PageRoute<T> extends ModalRoute<T> {
|
abstract class PageRoute<T> extends ModalRoute<T> {
|
||||||
/// Creates a modal route that replaces the entire screen.
|
/// Creates a modal route that replaces the entire screen.
|
||||||
PageRoute({
|
PageRoute({
|
||||||
@ -49,6 +56,13 @@ Widget _defaultTransitionsBuilder(BuildContext context, Animation<double> animat
|
|||||||
///
|
///
|
||||||
/// Callers must define the [pageBuilder] function which creates the route's
|
/// Callers must define the [pageBuilder] function which creates the route's
|
||||||
/// primary contents. To add transitions define the [transitionsBuilder] function.
|
/// primary contents. To add transitions define the [transitionsBuilder] function.
|
||||||
|
///
|
||||||
|
/// The `T` generic type argument corresponds to the type argument of the
|
||||||
|
/// created [Route] objects.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Route], which documents the meaning of the `T` generic type argument.
|
||||||
class PageRouteBuilder<T> extends PageRoute<T> {
|
class PageRouteBuilder<T> extends PageRoute<T> {
|
||||||
/// Creates a route that delegates to builder callbacks.
|
/// Creates a route that delegates to builder callbacks.
|
||||||
///
|
///
|
||||||
@ -86,6 +100,8 @@ class PageRouteBuilder<T> extends PageRoute<T> {
|
|||||||
///
|
///
|
||||||
/// See [ModalRoute.buildTransitions] for complete definition of the parameters.
|
/// See [ModalRoute.buildTransitions] for complete definition of the parameters.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
|
///
|
||||||
|
/// The default transition is a jump cut (i.e. no animation).
|
||||||
final RouteTransitionsBuilder transitionsBuilder;
|
final RouteTransitionsBuilder transitionsBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -34,6 +34,10 @@ import 'transitions.dart';
|
|||||||
// late StateSetter setState;
|
// late StateSetter setState;
|
||||||
|
|
||||||
/// A route that displays widgets in the [Navigator]'s [Overlay].
|
/// A route that displays widgets in the [Navigator]'s [Overlay].
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Route], which documents the meaning of the `T` generic type argument.
|
||||||
abstract class OverlayRoute<T> extends Route<T> {
|
abstract class OverlayRoute<T> extends Route<T> {
|
||||||
/// Creates a route that knows how to interact with an [Overlay].
|
/// Creates a route that knows how to interact with an [Overlay].
|
||||||
OverlayRoute({
|
OverlayRoute({
|
||||||
@ -85,6 +89,10 @@ abstract class OverlayRoute<T> extends Route<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A route with entrance and exit transitions.
|
/// A route with entrance and exit transitions.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Route], which documents the meaning of the `T` generic type argument.
|
||||||
abstract class TransitionRoute<T> extends OverlayRoute<T> {
|
abstract class TransitionRoute<T> extends OverlayRoute<T> {
|
||||||
/// Creates a route that animates itself when it is pushed or popped.
|
/// Creates a route that animates itself when it is pushed or popped.
|
||||||
TransitionRoute({
|
TransitionRoute({
|
||||||
@ -507,6 +515,10 @@ class LocalHistoryEntry {
|
|||||||
/// pop internally if its list of local history entries is non-empty. Rather
|
/// pop internally if its list of local history entries is non-empty. Rather
|
||||||
/// than being removed as the current route, the most recent [LocalHistoryEntry]
|
/// than being removed as the current route, the most recent [LocalHistoryEntry]
|
||||||
/// is removed from the list and its [LocalHistoryEntry.onRemove] is called.
|
/// is removed from the list and its [LocalHistoryEntry.onRemove] is called.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Route], which documents the meaning of the `T` generic type argument.
|
||||||
mixin LocalHistoryRoute<T> on Route<T> {
|
mixin LocalHistoryRoute<T> on Route<T> {
|
||||||
List<LocalHistoryEntry>? _localHistory;
|
List<LocalHistoryEntry>? _localHistory;
|
||||||
int _entriesImpliesAppBarDismissal = 0;
|
int _entriesImpliesAppBarDismissal = 0;
|
||||||
@ -946,6 +958,10 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
|
|||||||
///
|
///
|
||||||
/// The `T` type argument is the return value of the route. If there is no
|
/// The `T` type argument is the return value of the route. If there is no
|
||||||
/// return value, consider using `void` as the return value.
|
/// return value, consider using `void` as the return value.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Route], which further documents the meaning of the `T` generic type argument.
|
||||||
abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T> {
|
abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T> {
|
||||||
/// Creates a route that blocks interaction with previous routes.
|
/// Creates a route that blocks interaction with previous routes.
|
||||||
ModalRoute({
|
ModalRoute({
|
||||||
|
@ -26,6 +26,10 @@ import 'selection_container.dart';
|
|||||||
import 'text_editing_intents.dart';
|
import 'text_editing_intents.dart';
|
||||||
import 'text_selection.dart';
|
import 'text_selection.dart';
|
||||||
|
|
||||||
|
// Examples can assume:
|
||||||
|
// FocusNode _focusNode = FocusNode();
|
||||||
|
// late GlobalKey key;
|
||||||
|
|
||||||
const Set<PointerDeviceKind> _kLongPressSelectionDevices = <PointerDeviceKind>{
|
const Set<PointerDeviceKind> _kLongPressSelectionDevices = <PointerDeviceKind>{
|
||||||
PointerDeviceKind.touch,
|
PointerDeviceKind.touch,
|
||||||
PointerDeviceKind.stylus,
|
PointerDeviceKind.stylus,
|
||||||
@ -34,13 +38,22 @@ const Set<PointerDeviceKind> _kLongPressSelectionDevices = <PointerDeviceKind>{
|
|||||||
|
|
||||||
/// A widget that introduces an area for user selections.
|
/// A widget that introduces an area for user selections.
|
||||||
///
|
///
|
||||||
/// Flutter widgets are not selectable by default. To enable selection for
|
/// Flutter widgets are not selectable by default. Wrapping a widget subtree
|
||||||
/// a Flutter application, consider wrapping a portion of widget subtree with
|
/// with a [SelectableRegion] widget enables selection within that subtree (for
|
||||||
/// [SelectableRegion]. The wrapped subtree can be selected by users using mouse
|
/// example, [Text] widgets automatically look for selectable regions to enable
|
||||||
/// or touch gestures, e.g. users can select widgets by holding the mouse
|
/// selection). The wrapped subtree can be selected by users using mouse or
|
||||||
|
/// touch gestures, e.g. users can select widgets by holding the mouse
|
||||||
/// left-click and dragging across widgets, or they can use long press gestures
|
/// left-click and dragging across widgets, or they can use long press gestures
|
||||||
/// to select words on touch devices.
|
/// to select words on touch devices.
|
||||||
///
|
///
|
||||||
|
/// A [SelectableRegion] widget requires configuration; in particular specific
|
||||||
|
/// [selectionControls] must be provided.
|
||||||
|
///
|
||||||
|
/// The [SelectionArea] widget from the [material] library configures a
|
||||||
|
/// [SelectableRegion] in a platform-specific manner (e.g. using a Material
|
||||||
|
/// toolbar on Android, a Cupertino toolbar on iOS), and it may therefore be
|
||||||
|
/// simpler to use that widget rather than using [SelectableRegion] directly.
|
||||||
|
///
|
||||||
/// ## An overview of the selection system.
|
/// ## An overview of the selection system.
|
||||||
///
|
///
|
||||||
/// Every [Selectable] under the [SelectableRegion] can be selected. They form a
|
/// Every [Selectable] under the [SelectableRegion] can be selected. They form a
|
||||||
@ -77,7 +90,7 @@ const Set<PointerDeviceKind> _kLongPressSelectionDevices = <PointerDeviceKind>{
|
|||||||
/// MaterialApp(
|
/// MaterialApp(
|
||||||
/// home: SelectableRegion(
|
/// home: SelectableRegion(
|
||||||
/// selectionControls: materialTextSelectionControls,
|
/// selectionControls: materialTextSelectionControls,
|
||||||
/// focusNode: FocusNode(),
|
/// focusNode: _focusNode, // initialized to FocusNode()
|
||||||
/// child: Scaffold(
|
/// child: Scaffold(
|
||||||
/// appBar: AppBar(title: const Text('Flutter Code Sample')),
|
/// appBar: AppBar(title: const Text('Flutter Code Sample')),
|
||||||
/// body: ListView(
|
/// body: ListView(
|
||||||
@ -160,6 +173,16 @@ const Set<PointerDeviceKind> _kLongPressSelectionDevices = <PointerDeviceKind>{
|
|||||||
/// child selection area can not extend past its subtree, and the selection of
|
/// child selection area can not extend past its subtree, and the selection of
|
||||||
/// the parent selection area can not extend inside the child selection area.
|
/// the parent selection area can not extend inside the child selection area.
|
||||||
///
|
///
|
||||||
|
/// ## Tests
|
||||||
|
///
|
||||||
|
/// In a test, a region can be selected either by faking drag events (e.g. using
|
||||||
|
/// [WidgetTester.dragFrom]) or by sending intents to a widget inside the region
|
||||||
|
/// that has been given a [GlobalKey], e.g.:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// Actions.invoke(key.currentContext!, const SelectAllTextIntent(SelectionChangedCause.keyboard));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
/// * [SelectionArea], which creates a [SelectableRegion] with
|
/// * [SelectionArea], which creates a [SelectableRegion] with
|
||||||
/// platform-adaptive selection controls.
|
/// platform-adaptive selection controls.
|
||||||
@ -202,6 +225,9 @@ class SelectableRegion extends StatefulWidget {
|
|||||||
|
|
||||||
/// The delegate to build the selection handles and toolbar for mobile
|
/// The delegate to build the selection handles and toolbar for mobile
|
||||||
/// devices.
|
/// devices.
|
||||||
|
///
|
||||||
|
/// The [emptyTextSelectionControls] global variable provides a default
|
||||||
|
/// [TextSelectionControls] implementation with no controls.
|
||||||
final TextSelectionControls selectionControls;
|
final TextSelectionControls selectionControls;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -14,7 +14,8 @@ import 'framework.dart';
|
|||||||
///
|
///
|
||||||
/// The state of this container is a single selectable and will register
|
/// The state of this container is a single selectable and will register
|
||||||
/// itself to the [registrar] if provided. Otherwise, it will register to the
|
/// itself to the [registrar] if provided. Otherwise, it will register to the
|
||||||
/// [SelectionRegistrar] from the context.
|
/// [SelectionRegistrar] from the context. Consider using a [SelectionArea]
|
||||||
|
/// widget to provide a root registrar.
|
||||||
///
|
///
|
||||||
/// The containers handle the [SelectionEvent]s from the registered
|
/// The containers handle the [SelectionEvent]s from the registered
|
||||||
/// [SelectionRegistrar] and delegate the events to the [delegate].
|
/// [SelectionRegistrar] and delegate the events to the [delegate].
|
||||||
|
@ -533,6 +533,13 @@ class Text extends StatelessWidget {
|
|||||||
final ui.TextHeightBehavior? textHeightBehavior;
|
final ui.TextHeightBehavior? textHeightBehavior;
|
||||||
|
|
||||||
/// The color to use when painting the selection.
|
/// The color to use when painting the selection.
|
||||||
|
///
|
||||||
|
/// This is ignored if [SelectionContainer.maybeOf] returns null
|
||||||
|
/// in the [BuildContext] of the [Text] widget.
|
||||||
|
///
|
||||||
|
/// If null, the ambient [DefaultSelectionStyle] is used (if any); failing
|
||||||
|
/// that, the selection color defaults to [DefaultSelectionStyle.defaultColor]
|
||||||
|
/// (semi-transparent grey).
|
||||||
final Color? selectionColor;
|
final Color? selectionColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -558,7 +565,7 @@ class Text extends StatelessWidget {
|
|||||||
textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis,
|
textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis,
|
||||||
textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
|
textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
|
||||||
selectionRegistrar: registrar,
|
selectionRegistrar: registrar,
|
||||||
selectionColor: selectionColor ?? DefaultSelectionStyle.of(context).selectionColor,
|
selectionColor: selectionColor ?? DefaultSelectionStyle.of(context).selectionColor ?? DefaultSelectionStyle.defaultColor,
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
style: effectiveTextStyle,
|
style: effectiveTextStyle,
|
||||||
text: data,
|
text: data,
|
||||||
|
@ -26,6 +26,7 @@ import 'tap_region.dart';
|
|||||||
import 'ticker_provider.dart';
|
import 'ticker_provider.dart';
|
||||||
import 'transitions.dart';
|
import 'transitions.dart';
|
||||||
|
|
||||||
|
export 'package:flutter/rendering.dart' show TextSelectionPoint;
|
||||||
export 'package:flutter/services.dart' show TextSelectionDelegate;
|
export 'package:flutter/services.dart' show TextSelectionDelegate;
|
||||||
|
|
||||||
/// A duration that controls how often the drag selection update callback is
|
/// A duration that controls how often the drag selection update callback is
|
||||||
@ -76,6 +77,11 @@ class ToolbarItemsParentData extends ContainerBoxParentData<RenderBox> {
|
|||||||
/// implementer of the toolbar widget.
|
/// implementer of the toolbar widget.
|
||||||
///
|
///
|
||||||
/// Override text operations such as [handleCut] if needed.
|
/// Override text operations such as [handleCut] if needed.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [SelectionArea], which selects appropriate text selection controls
|
||||||
|
/// based on the current platform.
|
||||||
abstract class TextSelectionControls {
|
abstract class TextSelectionControls {
|
||||||
/// Builds a selection handle of the given `type`.
|
/// Builds a selection handle of the given `type`.
|
||||||
///
|
///
|
||||||
@ -97,20 +103,20 @@ abstract class TextSelectionControls {
|
|||||||
///
|
///
|
||||||
/// Typically displays buttons for copying and pasting text.
|
/// Typically displays buttons for copying and pasting text.
|
||||||
///
|
///
|
||||||
/// [globalEditableRegion] is the TextField size of the global coordinate system
|
/// The [globalEditableRegion] parameter is the TextField size of the global
|
||||||
/// in logical pixels.
|
/// coordinate system in logical pixels.
|
||||||
///
|
///
|
||||||
/// [textLineHeight] is the `preferredLineHeight` of the [RenderEditable] we
|
/// The [textLineHeight] parameter is the [RenderEditable.preferredLineHeight]
|
||||||
/// are building a toolbar for.
|
/// of the [RenderEditable] we are building a toolbar for.
|
||||||
///
|
///
|
||||||
/// The [position] is a general calculation midpoint parameter of the toolbar.
|
/// The [selectionMidpoint] parameter is a general calculation midpoint
|
||||||
/// If you want more detailed position information, can use [endpoints]
|
/// parameter of the toolbar. More detailed position information
|
||||||
/// to calculate it.
|
/// is computable from the [endpoints] parameter.
|
||||||
Widget buildToolbar(
|
Widget buildToolbar(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Rect globalEditableRegion,
|
Rect globalEditableRegion,
|
||||||
double textLineHeight,
|
double textLineHeight,
|
||||||
Offset position,
|
Offset selectionMidpoint,
|
||||||
List<TextSelectionPoint> endpoints,
|
List<TextSelectionPoint> endpoints,
|
||||||
TextSelectionDelegate delegate,
|
TextSelectionDelegate delegate,
|
||||||
ValueListenable<ClipboardStatus>? clipboardStatus,
|
ValueListenable<ClipboardStatus>? clipboardStatus,
|
||||||
@ -207,6 +213,55 @@ abstract class TextSelectionControls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Text selection controls that do not show any toolbars or handles.
|
||||||
|
///
|
||||||
|
/// This is a placeholder, suitable for temporary use during development, but
|
||||||
|
/// not practical for production. For example, it provides no way for the user
|
||||||
|
/// to interact with selections: no context menus on desktop, no toolbars or
|
||||||
|
/// drag handles on mobile, etc. For production, consider using
|
||||||
|
/// [MaterialTextSelectionControls] or creating a custom subclass of
|
||||||
|
/// [TextSelectionControls].
|
||||||
|
///
|
||||||
|
/// The [emptyTextSelectionControls] global variable has a
|
||||||
|
/// suitable instance of this class.
|
||||||
|
class EmptyTextSelectionControls extends TextSelectionControls {
|
||||||
|
@override
|
||||||
|
Size getHandleSize(double textLineHeight) => Size.zero;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildToolbar(
|
||||||
|
BuildContext context,
|
||||||
|
Rect globalEditableRegion,
|
||||||
|
double textLineHeight,
|
||||||
|
Offset selectionMidpoint,
|
||||||
|
List<TextSelectionPoint> endpoints,
|
||||||
|
TextSelectionDelegate delegate,
|
||||||
|
ValueListenable<ClipboardStatus>? clipboardStatus,
|
||||||
|
Offset? lastSecondaryTapDownPosition,
|
||||||
|
) => const SizedBox.shrink();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildHandle(BuildContext context, TextSelectionHandleType type, double textLineHeight, [VoidCallback? onTap]) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Offset getHandleAnchor(TextSelectionHandleType type, double textLineHeight) {
|
||||||
|
return Offset.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Text selection controls that do not show any toolbars or handles.
|
||||||
|
///
|
||||||
|
/// This is a placeholder, suitable for temporary use during development, but
|
||||||
|
/// not practical for production. For example, it provides no way for the user
|
||||||
|
/// to interact with selections: no context menus on desktop, no toolbars or
|
||||||
|
/// drag handles on mobile, etc. For production, consider using
|
||||||
|
/// [materialTextSelectionControls] or creating a custom subclass of
|
||||||
|
/// [TextSelectionControls].
|
||||||
|
final TextSelectionControls emptyTextSelectionControls = EmptyTextSelectionControls();
|
||||||
|
|
||||||
|
|
||||||
/// An object that manages a pair of text selection handles for a
|
/// An object that manages a pair of text selection handles for a
|
||||||
/// [RenderEditable].
|
/// [RenderEditable].
|
||||||
///
|
///
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../widgets/editable_text_utils.dart' show textOffsetToPosition;
|
import '../widgets/editable_text_utils.dart' show textOffsetToPosition;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../widgets/editable_text_utils.dart' show textOffsetToPosition;
|
import '../widgets/editable_text_utils.dart' show textOffsetToPosition;
|
||||||
|
153
packages/flutter/test/widgets/default_colors_test.dart
Normal file
153
packages/flutter/test/widgets/default_colors_test.dart
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
const double _crispText = 100.0; // this font size is selected to avoid needing any antialiasing.
|
||||||
|
const String _expText = 'Éxp'; // renders in Ahem as:
|
||||||
|
|
||||||
|
// ########
|
||||||
|
// ########
|
||||||
|
// ########
|
||||||
|
// ########
|
||||||
|
//
|
||||||
|
// ÉÉÉÉxxxxpppp
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Default background', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(const Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: Text(_expText, textDirection: TextDirection.ltr, style: TextStyle(color: Color(0xFF345678), fontSize: _crispText))),
|
||||||
|
);
|
||||||
|
await _expectColors(
|
||||||
|
tester,
|
||||||
|
find.byType(Align),
|
||||||
|
<Color>{ const Color(0x00000000), const Color(0xFF345678) },
|
||||||
|
<Offset, Color>{
|
||||||
|
Offset.zero: const Color(0xFF345678), // the text
|
||||||
|
const Offset(10, 10): const Color(0xFF345678), // the text
|
||||||
|
const Offset(50, 95): const Color(0x00000000), // the background (under the É)
|
||||||
|
const Offset(250, 50): const Color(0x00000000), // the text (above the p)
|
||||||
|
const Offset(250, 95): const Color(0xFF345678), // the text (the p)
|
||||||
|
const Offset(400, 400): const Color(0x00000000), // the background
|
||||||
|
const Offset(799, 599): const Color(0x00000000), // the background
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently.
|
||||||
|
|
||||||
|
testWidgets('Default text color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(const ColoredBox(
|
||||||
|
color: Color(0xFFABCDEF),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: Text('Éxp', textDirection: TextDirection.ltr, style: TextStyle(fontSize: _crispText)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await _expectColors(
|
||||||
|
tester,
|
||||||
|
find.byType(Align),
|
||||||
|
<Color>{ const Color(0xFFABCDEF), const Color(0xFFFFFFFF) },
|
||||||
|
<Offset, Color>{
|
||||||
|
Offset.zero: const Color(0xFFFFFFFF), // the text
|
||||||
|
const Offset(10, 10): const Color(0xFFFFFFFF), // the text
|
||||||
|
const Offset(50, 95): const Color(0xFFABCDEF), // the background (under the É)
|
||||||
|
const Offset(250, 50): const Color(0xFFABCDEF), // the text (above the p)
|
||||||
|
const Offset(250, 95): const Color(0xFFFFFFFF), // the text (the p)
|
||||||
|
const Offset(400, 400): const Color(0xFFABCDEF), // the background
|
||||||
|
const Offset(799, 599): const Color(0xFFABCDEF), // the background
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently.
|
||||||
|
|
||||||
|
testWidgets('Default text selection color', (WidgetTester tester) async {
|
||||||
|
final GlobalKey key = GlobalKey();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ColoredBox(
|
||||||
|
color: const Color(0xFFFFFFFF),
|
||||||
|
child: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: MediaQuery(
|
||||||
|
data: const MediaQueryData(),
|
||||||
|
child: Overlay(
|
||||||
|
initialEntries: <OverlayEntry>[
|
||||||
|
OverlayEntry(
|
||||||
|
builder: (BuildContext context) => SelectableRegion(
|
||||||
|
focusNode: FocusNode(),
|
||||||
|
selectionControls: emptyTextSelectionControls,
|
||||||
|
child: Align(
|
||||||
|
key: key,
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: const Text('Éxp', textDirection: TextDirection.ltr, style: TextStyle(fontSize: _crispText)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await _expectColors(
|
||||||
|
tester,
|
||||||
|
find.byType(Align),
|
||||||
|
<Color>{ const Color(0xFFFFFFFF) },
|
||||||
|
);
|
||||||
|
// fake a "select all" event to selecte the text
|
||||||
|
Actions.invoke(key.currentContext!, const SelectAllTextIntent(SelectionChangedCause.keyboard));
|
||||||
|
await tester.pump();
|
||||||
|
await _expectColors(
|
||||||
|
tester,
|
||||||
|
find.byType(Align),
|
||||||
|
<Color>{ const Color(0xFFFFFFFF), const Color(0xFFBFBFBF) }, // 0x80808080 blended with 0xFFFFFFFF
|
||||||
|
<Offset, Color>{
|
||||||
|
Offset.zero: const Color(0xFFBFBFBF), // the selected text
|
||||||
|
const Offset(10, 10): const Color(0xFFBFBFBF), // the selected text
|
||||||
|
const Offset(50, 95): const Color(0xFFBFBFBF), // the selected background (under the É)
|
||||||
|
const Offset(250, 50): const Color(0xFFBFBFBF), // the selected background (above the p)
|
||||||
|
const Offset(250, 95): const Color(0xFFBFBFBF), // the selected text (the p)
|
||||||
|
const Offset(400, 400): const Color(0xFFFFFFFF), // the background
|
||||||
|
const Offset(799, 599): const Color(0xFFFFFFFF), // the background
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently.
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getPixel(ByteData bytes, int x, int y, int width) {
|
||||||
|
final int offset = (x + y * width) * 4;
|
||||||
|
return Color.fromARGB(
|
||||||
|
bytes.getUint8(offset + 3),
|
||||||
|
bytes.getUint8(offset + 0),
|
||||||
|
bytes.getUint8(offset + 1),
|
||||||
|
bytes.getUint8(offset + 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _expectColors(WidgetTester tester, Finder finder, Set<Color> allowedColors, [ Map<Offset, Color>? spotChecks ]) async {
|
||||||
|
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||||
|
final ui.Image image = (await binding.runAsync<ui.Image>(() => captureImage(finder.evaluate().single)))!;
|
||||||
|
final ByteData bytes = (await binding.runAsync<ByteData?>(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!;
|
||||||
|
final Set<int> actualColorValues = <int>{};
|
||||||
|
for (int offset = 0; offset < bytes.lengthInBytes; offset += 4) {
|
||||||
|
actualColorValues.add((bytes.getUint8(offset + 3) << 24) +
|
||||||
|
(bytes.getUint8(offset + 0) << 16) +
|
||||||
|
(bytes.getUint8(offset + 1) << 8) +
|
||||||
|
(bytes.getUint8(offset + 2)));
|
||||||
|
}
|
||||||
|
final Set<Color> actualColors = actualColorValues.map((int value) => Color(value)).toSet();
|
||||||
|
expect(actualColors, allowedColors);
|
||||||
|
spotChecks?.forEach((Offset position, Color expected) {
|
||||||
|
assert(position.dx.round() >= 0);
|
||||||
|
assert(position.dx.round() < image.width);
|
||||||
|
assert(position.dy.round() >= 0);
|
||||||
|
assert(position.dy.round() < image.height);
|
||||||
|
final Offset precisePosition = position * binding.window.devicePixelRatio;
|
||||||
|
final Color actual = _getPixel(bytes, precisePosition.dx.round(), precisePosition.dy.round(), image.width);
|
||||||
|
expect(actual, expected, reason: 'Pixel at $position is $actual but expected $expected.');
|
||||||
|
});
|
||||||
|
}
|
@ -56,6 +56,7 @@ library flutter_test;
|
|||||||
export 'dart:async' show Future;
|
export 'dart:async' show Future;
|
||||||
|
|
||||||
export 'src/_goldens_io.dart' if (dart.library.html) 'src/_goldens_web.dart';
|
export 'src/_goldens_io.dart' if (dart.library.html) 'src/_goldens_web.dart';
|
||||||
|
export 'src/_matchers_io.dart' if (dart.library.html) 'src/_matchers_web.dart';
|
||||||
export 'src/accessibility.dart';
|
export 'src/accessibility.dart';
|
||||||
export 'src/all_elements.dart';
|
export 'src/all_elements.dart';
|
||||||
export 'src/animation_sheet.dart';
|
export 'src/animation_sheet.dart';
|
||||||
|
@ -30,6 +30,15 @@ Future<ui.Image> captureImage(Element element) {
|
|||||||
return layer.toImage(renderObject.paintBounds);
|
return layer.toImage(renderObject.paintBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not [captureImage] is supported.
|
||||||
|
///
|
||||||
|
/// This can be used to skip tests on platforms that don't support
|
||||||
|
/// capturing images.
|
||||||
|
///
|
||||||
|
/// Currently this is true except when tests are running in the context of a web
|
||||||
|
/// browser (`flutter test --platform chrome`).
|
||||||
|
const bool canCaptureImage = true;
|
||||||
|
|
||||||
/// The matcher created by [matchesGoldenFile]. This class is enabled when the
|
/// The matcher created by [matchesGoldenFile]. This class is enabled when the
|
||||||
/// test is running on a VM using conditional import.
|
/// test is running on a VM using conditional import.
|
||||||
class MatchesGoldenFile extends AsyncMatcher {
|
class MatchesGoldenFile extends AsyncMatcher {
|
||||||
@ -84,7 +93,7 @@ class MatchesGoldenFile extends AsyncMatcher {
|
|||||||
throw AssertionError('must provide a Finder, Image, Future<Image>, List<int>, or Future<List<int>>');
|
throw AssertionError('must provide a Finder, Image, Future<Image>, List<int>, or Future<List<int>>');
|
||||||
}
|
}
|
||||||
|
|
||||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance;
|
||||||
return binding.runAsync<String?>(() async {
|
return binding.runAsync<String?>(() async {
|
||||||
final ui.Image? image = await imageFuture;
|
final ui.Image? image = await imageFuture;
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
|
@ -18,6 +18,15 @@ Future<ui.Image> captureImage(Element element) {
|
|||||||
throw UnsupportedError('captureImage is not supported on the web.');
|
throw UnsupportedError('captureImage is not supported on the web.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not [captureImage] is supported.
|
||||||
|
///
|
||||||
|
/// This can be used to skip tests on platforms that don't support
|
||||||
|
/// capturing images.
|
||||||
|
///
|
||||||
|
/// Currently this is true except when tests are running in the context of a web
|
||||||
|
/// browser (`flutter test --platform chrome`).
|
||||||
|
const bool canCaptureImage = false;
|
||||||
|
|
||||||
/// The matcher created by [matchesGoldenFile]. This class is enabled when the
|
/// The matcher created by [matchesGoldenFile]. This class is enabled when the
|
||||||
/// test is running in a web browser using conditional import.
|
/// test is running in a web browser using conditional import.
|
||||||
class MatchesGoldenFile extends AsyncMatcher {
|
class MatchesGoldenFile extends AsyncMatcher {
|
||||||
@ -47,7 +56,7 @@ class MatchesGoldenFile extends AsyncMatcher {
|
|||||||
final Element element = elements.single;
|
final Element element = elements.single;
|
||||||
final RenderObject renderObject = _findRepaintBoundary(element);
|
final RenderObject renderObject = _findRepaintBoundary(element);
|
||||||
final Size size = renderObject.paintBounds.size;
|
final Size size = renderObject.paintBounds.size;
|
||||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance;
|
||||||
final Element e = binding.renderViewElement!;
|
final Element e = binding.renderViewElement!;
|
||||||
|
|
||||||
// Unlike `flutter_tester`, we don't have the ability to render an element
|
// Unlike `flutter_tester`, we don't have the ability to render an element
|
||||||
|
@ -1131,28 +1131,45 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
|
|
||||||
addTime(additionalTime);
|
addTime(additionalTime);
|
||||||
|
|
||||||
return realAsyncZone.run<Future<T?>>(() async {
|
return realAsyncZone.run<Future<T?>>(() {
|
||||||
|
final Completer<T?> result = Completer<T?>();
|
||||||
_pendingAsyncTasks = Completer<void>();
|
_pendingAsyncTasks = Completer<void>();
|
||||||
T? result;
|
|
||||||
try {
|
try {
|
||||||
result = await callback();
|
callback().then(result.complete).catchError(
|
||||||
|
(Object exception, StackTrace stack) {
|
||||||
|
FlutterError.reportError(FlutterErrorDetails(
|
||||||
|
exception: exception,
|
||||||
|
stack: stack,
|
||||||
|
library: 'Flutter test framework',
|
||||||
|
context: ErrorDescription('while running async test code'),
|
||||||
|
informationCollector: () {
|
||||||
|
return <DiagnosticsNode>[
|
||||||
|
ErrorHint('The exception was caught asynchronously.'),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
));
|
||||||
|
result.complete(null);
|
||||||
|
},
|
||||||
|
);
|
||||||
} catch (exception, stack) {
|
} catch (exception, stack) {
|
||||||
FlutterError.reportError(FlutterErrorDetails(
|
FlutterError.reportError(FlutterErrorDetails(
|
||||||
exception: exception,
|
exception: exception,
|
||||||
stack: stack,
|
stack: stack,
|
||||||
library: 'Flutter test framework',
|
library: 'Flutter test framework',
|
||||||
context: ErrorDescription('while running async test code'),
|
context: ErrorDescription('while running async test code'),
|
||||||
|
informationCollector: () {
|
||||||
|
return <DiagnosticsNode>[
|
||||||
|
ErrorHint('The exception was caught synchronously.'),
|
||||||
|
];
|
||||||
|
},
|
||||||
));
|
));
|
||||||
} finally {
|
result.complete(null);
|
||||||
// We complete the _pendingAsyncTasks future successfully regardless of
|
}
|
||||||
// whether an exception occurred because in the case of an exception,
|
result.future.whenComplete(() {
|
||||||
// we already reported the exception to FlutterError. Moreover,
|
|
||||||
// completing the future with an error would trigger an unhandled
|
|
||||||
// exception due to zone error boundaries.
|
|
||||||
_pendingAsyncTasks!.complete();
|
_pendingAsyncTasks!.complete();
|
||||||
_pendingAsyncTasks = null;
|
_pendingAsyncTasks = null;
|
||||||
}
|
});
|
||||||
return result;
|
return result.future;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@ class _BufferGoldenMatcher extends AsyncMatcher {
|
|||||||
/// golden files. This parameter is optional.
|
/// golden files. This parameter is optional.
|
||||||
///
|
///
|
||||||
/// {@tool snippet}
|
/// {@tool snippet}
|
||||||
/// Sample invocations of [matchesGoldenFile].
|
/// Sample invocations of [bufferMatchesGoldenFile].
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// await expectLater(
|
/// await expectLater(
|
||||||
/// const <int>[],
|
/// const <int>[ /* bytes... */ ],
|
||||||
/// bufferMatchesGoldenFile('sample.png'),
|
/// bufferMatchesGoldenFile('sample.png'),
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -2030,7 +2030,7 @@ class _MatchesReferenceImage extends AsyncMatcher {
|
|||||||
imageFuture = captureImage(elements.single);
|
imageFuture = captureImage(elements.single);
|
||||||
}
|
}
|
||||||
|
|
||||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance;
|
||||||
return binding.runAsync<String?>(() async {
|
return binding.runAsync<String?>(() async {
|
||||||
final ui.Image image = await imageFuture;
|
final ui.Image image = await imageFuture;
|
||||||
final ByteData? bytes = await image.toByteData();
|
final ByteData? bytes = await image.toByteData();
|
||||||
|
@ -630,6 +630,23 @@ void main() {
|
|||||||
key: 'abczed',
|
key: 'abczed',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('control test (return value)', (WidgetTester tester) async {
|
||||||
|
final String? result = await tester.binding.runAsync<String>(() async => 'Judy Turner');
|
||||||
|
expect(result, 'Judy Turner');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('async throw', (WidgetTester tester) async {
|
||||||
|
final String? result = await tester.binding.runAsync<Never>(() async => throw Exception('Lois Dilettente'));
|
||||||
|
expect(result, isNull);
|
||||||
|
expect(tester.takeException(), isNotNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('sync throw', (WidgetTester tester) async {
|
||||||
|
final String? result = await tester.binding.runAsync<Never>(() => throw Exception('Butch Barton'));
|
||||||
|
expect(result, isNull);
|
||||||
|
expect(tester.takeException(), isNotNull);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('showKeyboard', () {
|
group('showKeyboard', () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user