WidgetStateInputBorder
(#157190)
**Changes** - Add `WidgetStateInputBorder` class, with `.resolveWith()` and `.fromMap()` constructors - Deprecate `MaterialStateOutlineInputBorder` and `MaterialStateUnderlineInputBorder` and provide data-driven fixes <br> **Other changes** based on https://github.com/flutter/flutter/pull/154972#pullrequestreview-2344092821 - Fix documentation copy-paste typo ("OutlinedBorder" â "InputBorder") - Add test to ensure borders are painted correctly - Add DartPad sample & relevant test
This commit is contained in:
parent
4af4a9b282
commit
ea0fda51ef
@ -0,0 +1,114 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Flutter code sample for [WidgetStateInputBorder].
|
||||||
|
|
||||||
|
void main() => runApp(const WidgetStateInputBorderExampleApp());
|
||||||
|
|
||||||
|
/// This extension isn't necessary when WidgetState properties are
|
||||||
|
/// configured using [WidgetStateMapper] objects.
|
||||||
|
///
|
||||||
|
/// But sometimes it makes sense to use a resolveWith() callback,
|
||||||
|
/// and these getters make those callbacks a bit more readable!
|
||||||
|
extension WidgetStateHelpers on Set<WidgetState> {
|
||||||
|
bool get focused => contains(WidgetState.focused);
|
||||||
|
bool get hovered => contains(WidgetState.hovered);
|
||||||
|
bool get disabled => contains(WidgetState.disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetStateInputBorderExampleApp extends StatelessWidget {
|
||||||
|
const WidgetStateInputBorderExampleApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('WidgetStateInputBorder Example'),
|
||||||
|
),
|
||||||
|
body: const Center(child: PageContent()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PageContent extends StatefulWidget {
|
||||||
|
const PageContent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PageContent> createState() => _PageContentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PageContentState extends State<PageContent> {
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
const Spacer(flex: 8),
|
||||||
|
Focus(
|
||||||
|
child: WidgetStateInputBorderExample(enabled: enabled),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
FilterChip(
|
||||||
|
label: const Text('enable text field'),
|
||||||
|
selected: enabled,
|
||||||
|
onSelected: (bool selected) {
|
||||||
|
setState(() {
|
||||||
|
enabled = selected;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Spacer(flex: 8),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetStateInputBorderExample extends StatelessWidget {
|
||||||
|
const WidgetStateInputBorderExample({super.key, required this.enabled});
|
||||||
|
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
|
/// A global or static function can be referenced in a `const` constructor,
|
||||||
|
/// such as [WidgetStateInputBorder.resolveWith].
|
||||||
|
///
|
||||||
|
/// Constant values can be useful for promoting accurate equality checks,
|
||||||
|
/// such as when rebuilding a [Theme] widget.
|
||||||
|
static UnderlineInputBorder veryCoolBorder(Set<WidgetState> states) {
|
||||||
|
if (states.disabled) {
|
||||||
|
return const UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.grey),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color dullViolet = Color(0xFF502080);
|
||||||
|
|
||||||
|
return UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
width: states.hovered ? 6 : (states.focused ? 3 : 1.5),
|
||||||
|
color: states.focused ? Colors.deepPurpleAccent : dullViolet,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final InputDecoration decoration = InputDecoration(
|
||||||
|
border: const WidgetStateInputBorder.resolveWith(veryCoolBorder),
|
||||||
|
labelText: enabled ? 'Type something awesome…' : '(click below to enable)',
|
||||||
|
);
|
||||||
|
|
||||||
|
return AnimatedFractionallySizedBox(
|
||||||
|
duration: Durations.medium1,
|
||||||
|
curve: Curves.ease,
|
||||||
|
widthFactor: Focus.of(context).hasFocus ? 0.9 : 0.6,
|
||||||
|
child: TextField(decoration: decoration, enabled: enabled),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// 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/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_api_samples/material/widget_state_input_border/widget_state_input_border.0.dart' as example;
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('InputBorder appearance matches configuration', (WidgetTester tester) async {
|
||||||
|
const WidgetStateInputBorder inputBorder = WidgetStateInputBorder.resolveWith(
|
||||||
|
example.WidgetStateInputBorderExample.veryCoolBorder,
|
||||||
|
);
|
||||||
|
|
||||||
|
void expectBorderToMatch(Set<WidgetState> states) {
|
||||||
|
final RenderBox renderBox = tester.renderObject(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(TextField),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final BorderSide side = inputBorder.resolve(states).borderSide;
|
||||||
|
expect(
|
||||||
|
renderBox,
|
||||||
|
paints..line(color: side.color, strokeWidth: side.width),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.WidgetStateInputBorderExampleApp(),
|
||||||
|
);
|
||||||
|
expectBorderToMatch(const <WidgetState>{WidgetState.disabled});
|
||||||
|
|
||||||
|
await tester.tap(find.byType(FilterChip));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expectBorderToMatch(const <WidgetState>{});
|
||||||
|
|
||||||
|
await tester.tap(find.byType(TextField));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expectBorderToMatch(const <WidgetState>{WidgetState.focused});
|
||||||
|
|
||||||
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||||
|
await gesture.addPointer(location: tester.getCenter(find.byType(TextField)));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expectBorderToMatch(const <WidgetState>{WidgetState.focused, WidgetState.hovered});
|
||||||
|
});
|
||||||
|
}
|
@ -26,6 +26,34 @@
|
|||||||
# * ThemeDate: fix_theme_data.yaml
|
# * ThemeDate: fix_theme_data.yaml
|
||||||
version: 1
|
version: 1
|
||||||
transforms:
|
transforms:
|
||||||
|
# Changes made in https://github.com/flutter/flutter/pull/154972
|
||||||
|
- title: "Replace with 'WidgetStateInputBorder'"
|
||||||
|
date: 2024-02-01
|
||||||
|
element:
|
||||||
|
uris: [ 'material.dart' ]
|
||||||
|
constructor: 'resolveWith'
|
||||||
|
inClass: 'MaterialStateOutlineInputBorder'
|
||||||
|
changes:
|
||||||
|
- kind: 'replacedBy'
|
||||||
|
newElement:
|
||||||
|
uris: [ 'material.dart' ]
|
||||||
|
constructor: 'resolveWith'
|
||||||
|
inClass: 'WidgetStateInputBorder'
|
||||||
|
|
||||||
|
# Changes made in https://github.com/flutter/flutter/pull/154972
|
||||||
|
- title: "Replace with 'WidgetStateInputBorder'"
|
||||||
|
date: 2024-02-01
|
||||||
|
element:
|
||||||
|
uris: [ 'material.dart' ]
|
||||||
|
constructor: 'resolveWith'
|
||||||
|
inClass: 'MaterialStateUnderlineInputBorder'
|
||||||
|
changes:
|
||||||
|
- kind: 'replacedBy'
|
||||||
|
newElement:
|
||||||
|
uris: [ 'material.dart' ]
|
||||||
|
constructor: 'resolveWith'
|
||||||
|
inClass: 'WidgetStateInputBorder'
|
||||||
|
|
||||||
# Changes made in https://github.com/flutter/flutter/pull/142151
|
# Changes made in https://github.com/flutter/flutter/pull/142151
|
||||||
- title: "Replace with 'WidgetState'"
|
- title: "Replace with 'WidgetState'"
|
||||||
date: 2024-02-01
|
date: 2024-02-01
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
/// @docImport 'list_tile.dart';
|
/// @docImport 'list_tile.dart';
|
||||||
/// @docImport 'outlined_button.dart';
|
/// @docImport 'outlined_button.dart';
|
||||||
/// @docImport 'text_button.dart';
|
/// @docImport 'text_button.dart';
|
||||||
|
/// @docImport 'text_field.dart';
|
||||||
/// @docImport 'time_picker_theme.dart';
|
/// @docImport 'time_picker_theme.dart';
|
||||||
library;
|
library;
|
||||||
|
|
||||||
@ -301,9 +302,19 @@ typedef MaterialStateTextStyle = WidgetStateTextStyle;
|
|||||||
/// [MaterialStateOutlineInputBorder] and override its [resolve] method. You'll also need
|
/// [MaterialStateOutlineInputBorder] and override its [resolve] method. You'll also need
|
||||||
/// to provide a `defaultValue` to the super constructor, so that we can know
|
/// to provide a `defaultValue` to the super constructor, so that we can know
|
||||||
/// at compile-time what its default color is.
|
/// at compile-time what its default color is.
|
||||||
|
@Deprecated(
|
||||||
|
'Use WidgetStateInputBorder instead. '
|
||||||
|
'Renamed to match other WidgetStateProperty objects. '
|
||||||
|
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||||
|
)
|
||||||
abstract class MaterialStateOutlineInputBorder extends OutlineInputBorder implements MaterialStateProperty<InputBorder> {
|
abstract class MaterialStateOutlineInputBorder extends OutlineInputBorder implements MaterialStateProperty<InputBorder> {
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||||
/// const constructors so that they can be used in const expressions.
|
/// const constructors so that they can be used in const expressions.
|
||||||
|
@Deprecated(
|
||||||
|
'Use WidgetStateInputBorder instead. '
|
||||||
|
'Renamed to match other WidgetStateProperty objects. '
|
||||||
|
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||||
|
)
|
||||||
const MaterialStateOutlineInputBorder();
|
const MaterialStateOutlineInputBorder();
|
||||||
|
|
||||||
/// Creates a [MaterialStateOutlineInputBorder] from a [MaterialPropertyResolver<InputBorder>]
|
/// Creates a [MaterialStateOutlineInputBorder] from a [MaterialPropertyResolver<InputBorder>]
|
||||||
@ -314,6 +325,11 @@ abstract class MaterialStateOutlineInputBorder extends OutlineInputBorder implem
|
|||||||
///
|
///
|
||||||
/// The given callback parameter must return a non-null text style in the default
|
/// The given callback parameter must return a non-null text style in the default
|
||||||
/// state.
|
/// state.
|
||||||
|
@Deprecated(
|
||||||
|
'Use WidgetStateInputBorder.resolveWith() instead. '
|
||||||
|
'Renamed to match other WidgetStateProperty objects. '
|
||||||
|
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||||
|
)
|
||||||
const factory MaterialStateOutlineInputBorder.resolveWith(MaterialPropertyResolver<InputBorder> callback) = _MaterialStateOutlineInputBorder;
|
const factory MaterialStateOutlineInputBorder.resolveWith(MaterialPropertyResolver<InputBorder> callback) = _MaterialStateOutlineInputBorder;
|
||||||
|
|
||||||
/// Returns a [InputBorder] that's to be used when a Material component is in the
|
/// Returns a [InputBorder] that's to be used when a Material component is in the
|
||||||
@ -363,9 +379,19 @@ class _MaterialStateOutlineInputBorder extends MaterialStateOutlineInputBorder {
|
|||||||
/// [MaterialStateUnderlineInputBorder] and override its [resolve] method. You'll also need
|
/// [MaterialStateUnderlineInputBorder] and override its [resolve] method. You'll also need
|
||||||
/// to provide a `defaultValue` to the super constructor, so that we can know
|
/// to provide a `defaultValue` to the super constructor, so that we can know
|
||||||
/// at compile-time what its default color is.
|
/// at compile-time what its default color is.
|
||||||
|
@Deprecated(
|
||||||
|
'Use WidgetStateInputBorder instead. '
|
||||||
|
'Renamed to match other WidgetStateProperty objects. '
|
||||||
|
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||||
|
)
|
||||||
abstract class MaterialStateUnderlineInputBorder extends UnderlineInputBorder implements MaterialStateProperty<InputBorder> {
|
abstract class MaterialStateUnderlineInputBorder extends UnderlineInputBorder implements MaterialStateProperty<InputBorder> {
|
||||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||||
/// const constructors so that they can be used in const expressions.
|
/// const constructors so that they can be used in const expressions.
|
||||||
|
@Deprecated(
|
||||||
|
'Use WidgetStateInputBorder instead. '
|
||||||
|
'Renamed to match other WidgetStateProperty objects. '
|
||||||
|
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||||
|
)
|
||||||
const MaterialStateUnderlineInputBorder();
|
const MaterialStateUnderlineInputBorder();
|
||||||
|
|
||||||
/// Creates a [MaterialStateUnderlineInputBorder] from a [MaterialPropertyResolver<InputBorder>]
|
/// Creates a [MaterialStateUnderlineInputBorder] from a [MaterialPropertyResolver<InputBorder>]
|
||||||
@ -376,6 +402,11 @@ abstract class MaterialStateUnderlineInputBorder extends UnderlineInputBorder im
|
|||||||
///
|
///
|
||||||
/// The given callback parameter must return a non-null text style in the default
|
/// The given callback parameter must return a non-null text style in the default
|
||||||
/// state.
|
/// state.
|
||||||
|
@Deprecated(
|
||||||
|
'Use WidgetStateInputBorder.resolveWith() instead. '
|
||||||
|
'Renamed to match other WidgetStateProperty objects. '
|
||||||
|
'This feature was deprecated after v3.26.0-0.1.pre.'
|
||||||
|
)
|
||||||
const factory MaterialStateUnderlineInputBorder.resolveWith(MaterialPropertyResolver<InputBorder> callback) = _MaterialStateUnderlineInputBorder;
|
const factory MaterialStateUnderlineInputBorder.resolveWith(MaterialPropertyResolver<InputBorder> callback) = _MaterialStateUnderlineInputBorder;
|
||||||
|
|
||||||
/// Returns a [InputBorder] that's to be used when a Material component is in the
|
/// Returns a [InputBorder] that's to be used when a Material component is in the
|
||||||
@ -400,6 +431,66 @@ class _MaterialStateUnderlineInputBorder extends MaterialStateUnderlineInputBord
|
|||||||
InputBorder resolve(Set<MaterialState> states) => _resolve(states);
|
InputBorder resolve(Set<MaterialState> states) => _resolve(states);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines an [InputBorder] that is also a [WidgetStateProperty].
|
||||||
|
///
|
||||||
|
/// This class exists to enable widgets with [InputBorder] valued properties
|
||||||
|
/// to also accept [WidgetStateProperty] objects.
|
||||||
|
///
|
||||||
|
/// [WidgetStateInputBorder] should only be used with widgets that document
|
||||||
|
/// their support, like [InputDecoration.border].
|
||||||
|
///
|
||||||
|
/// A [WidgetStateInputBorder] can be created by:
|
||||||
|
/// 1. Creating a class that extends [OutlineInputBorder] or [UnderlineInputBorder]
|
||||||
|
/// and implements [WidgetStateInputBorder]. The class would also need to
|
||||||
|
/// override the [resolve] method.
|
||||||
|
/// 2. Using [WidgetStateInputBorder.resolveWith] with a callback that
|
||||||
|
/// resolves the input border in the given states.
|
||||||
|
/// 3. Using [WidgetStateInputBorder.fromMap] to assign a border with a [WidgetStateMap].
|
||||||
|
///
|
||||||
|
/// {@tool dartpad}
|
||||||
|
/// This example shows how to use [WidgetStateInputBorder] to create
|
||||||
|
/// a [TextField] with an appearance that responds to user interaction.
|
||||||
|
///
|
||||||
|
/// ** See code in examples/api/lib/material/widget_state_input_border/widget_state_input_border.0.dart **
|
||||||
|
/// {@end-tool}
|
||||||
|
abstract interface class WidgetStateInputBorder implements InputBorder, WidgetStateProperty<InputBorder> {
|
||||||
|
/// Creates a [WidgetStateInputBorder] using a [WidgetPropertyResolver]
|
||||||
|
/// callback.
|
||||||
|
///
|
||||||
|
/// This constructor should only be used for fields that support
|
||||||
|
/// [WidgetStateInputBorder], such as [InputDecoration.border]
|
||||||
|
/// (if used as a regular [InputBorder], it acts the same as
|
||||||
|
/// an empty `OutlineInputBorder()` constructor).
|
||||||
|
const factory WidgetStateInputBorder.resolveWith(
|
||||||
|
WidgetPropertyResolver<InputBorder> callback,
|
||||||
|
) = _WidgetStateInputBorder;
|
||||||
|
|
||||||
|
/// Creates a [WidgetStateOutlinedBorder] from a [WidgetStateMap].
|
||||||
|
///
|
||||||
|
/// {@macro flutter.widgets.WidgetStateProperty.fromMap}
|
||||||
|
/// It should only be used for fields that support [WidgetStateOutlinedBorder]
|
||||||
|
/// objects, such as [InputDecoration.border]
|
||||||
|
/// (throws an error if used as a regular [OutlinedBorder]).
|
||||||
|
///
|
||||||
|
/// {@macro flutter.widgets.WidgetState.any}
|
||||||
|
const factory WidgetStateInputBorder.fromMap(
|
||||||
|
WidgetStateMap<InputBorder> map,
|
||||||
|
) = _WidgetInputBorderMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WidgetStateInputBorder extends OutlineInputBorder implements WidgetStateInputBorder {
|
||||||
|
const _WidgetStateInputBorder(this._resolve);
|
||||||
|
|
||||||
|
final WidgetPropertyResolver<InputBorder> _resolve;
|
||||||
|
|
||||||
|
@override
|
||||||
|
InputBorder resolve(Set<WidgetState> states) => _resolve(states);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WidgetInputBorderMapper extends WidgetStateMapper<InputBorder> implements WidgetStateInputBorder {
|
||||||
|
const _WidgetInputBorderMapper(super.map);
|
||||||
|
}
|
||||||
|
|
||||||
/// Interface for classes that [resolve] to a value of type `T` based
|
/// Interface for classes that [resolve] to a value of type `T` based
|
||||||
/// on a widget's interactive "state", which is defined as a set
|
/// on a widget's interactive "state", which is defined as a set
|
||||||
/// of [MaterialState]s.
|
/// of [MaterialState]s.
|
||||||
|
@ -7189,6 +7189,57 @@ void main() {
|
|||||||
expect(decoration.constraints, const BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40));
|
expect(decoration.constraints, const BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('InputDecoration with WidgetStateInputBorder', (WidgetTester tester) async {
|
||||||
|
const WidgetStateInputBorder outlineInputBorder = WidgetStateInputBorder.fromMap(
|
||||||
|
<WidgetStatesConstraint, InputBorder>{
|
||||||
|
WidgetState.focused: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.blue, width: 4.0),
|
||||||
|
),
|
||||||
|
WidgetState.hovered: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.cyan, width: 8.0),
|
||||||
|
),
|
||||||
|
WidgetState.any: OutlineInputBorder(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderObject getBorder() {
|
||||||
|
return tester.renderObject(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(TextField),
|
||||||
|
matching: find.byType(CustomPaint),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final FocusNode focusNode = FocusNode();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: TextField(
|
||||||
|
focusNode: focusNode,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: outlineInputBorder,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(getBorder(), paints..rrect(strokeWidth: 1.0));
|
||||||
|
|
||||||
|
focusNode.requestFocus();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(getBorder(), paints..rrect(color: Colors.blue, strokeWidth: 4.0));
|
||||||
|
|
||||||
|
focusNode.unfocus();
|
||||||
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||||
|
await gesture.addPointer(location: tester.getCenter(find.byType(TextField)));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(getBorder(), paints..rrect(color: Colors.cyan, strokeWidth: 8.0));
|
||||||
|
|
||||||
|
focusNode.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('InputDecorator constrained to 0x0', (WidgetTester tester) async {
|
testWidgets('InputDecorator constrained to 0x0', (WidgetTester tester) async {
|
||||||
// Regression test for https://github.com/flutter/flutter/issues/17710
|
// Regression test for https://github.com/flutter/flutter/issues/17710
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
|
@ -306,4 +306,12 @@ void main() {
|
|||||||
|
|
||||||
final PlatformMenuBar platformMenuBar = PlatformMenuBar(menus: <PlatformMenuItem>[], body: const SizedBox());
|
final PlatformMenuBar platformMenuBar = PlatformMenuBar(menus: <PlatformMenuItem>[], body: const SizedBox());
|
||||||
final Widget bodyValue = platformMenuBar.body;
|
final Widget bodyValue = platformMenuBar.body;
|
||||||
|
|
||||||
|
// Changes made in https://github.com/flutter/flutter/pull/154972
|
||||||
|
final InputBorder outlineBorder = MaterialStateOutlineInputBorder.resolveWith(
|
||||||
|
(states) => const OutlineInputBorder(),
|
||||||
|
);
|
||||||
|
final InputBorder underlineBorder = MaterialStateUnderlineInputBorder.resolveWith(
|
||||||
|
(states) => const UnderlineInputBorder(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -302,4 +302,12 @@ void main() {
|
|||||||
|
|
||||||
final PlatformMenuBar platformMenuBar = PlatformMenuBar(menus: <PlatformMenuItem>[], child: const SizedBox());
|
final PlatformMenuBar platformMenuBar = PlatformMenuBar(menus: <PlatformMenuItem>[], child: const SizedBox());
|
||||||
final Widget bodyValue = platformMenuBar.child;
|
final Widget bodyValue = platformMenuBar.child;
|
||||||
|
|
||||||
|
// Changes made in https://github.com/flutter/flutter/pull/154972
|
||||||
|
final InputBorder outlineBorder = WidgetStateInputBorder.resolveWith(
|
||||||
|
(states) => const OutlineInputBorder(),
|
||||||
|
);
|
||||||
|
final InputBorder underlineBorder = WidgetStateInputBorder.resolveWith(
|
||||||
|
(states) => const UnderlineInputBorder(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user