mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add factory constructors for shorthands that would collide (#165597)
EdgeInsets and EdgeInsetsDirectional are subtypes of EdgeInsetsGeometry. The both have only, all, and symmetric constructors, which creates collisions in a world where Dart support shorthand notation such as: ```dart Padding( padding: .only(bottom: 10.0), ), ``` The same goes for all these classes: - AlignmentGeometry - Alignment - AlignmentDirectional - BorderRadiusGeometry - BorderRadius - BorderRadiusDirectional - BoxBorder - Border - BorderDirectional - EdgeInsetsGeometry - EdgeInsets - EdgeInsetsDirectional The shorthands feature is not planning to exhaustively check subtypes. However, these classes were identified as the most impactful for the shorthands feature (❗ ). Adding these factories in the super classes enables future shorthand support. Prior in https://github.com/flutter/flutter/pull/159703 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
355129961c
commit
7561caa71f
@ -26,6 +26,12 @@ abstract class AlignmentGeometry {
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const AlignmentGeometry();
|
||||
|
||||
/// Creates an [Alignment].
|
||||
const factory AlignmentGeometry.xy(double x, double y) = Alignment;
|
||||
|
||||
/// Creates a directional alignment, or [AlignmentDirectional].
|
||||
const factory AlignmentGeometry.directional(double start, double y) = AlignmentDirectional;
|
||||
|
||||
double get _x;
|
||||
|
||||
double get _start;
|
||||
|
||||
@ -26,6 +26,68 @@ abstract class BorderRadiusGeometry {
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const BorderRadiusGeometry();
|
||||
|
||||
/// Creates a [BorderRadius] where all radii are `radius`.
|
||||
// The radius applies equally on all sides, so BorderRadiusDirectional is
|
||||
// irrelevant in this case.
|
||||
const factory BorderRadiusGeometry.all(Radius radius) = BorderRadius.all;
|
||||
|
||||
/// Creates a [BorderRadius] where all radii are [Radius.circular(radius)].
|
||||
// The radius applies equally on all sides, so BorderRadiusDirectional is
|
||||
// irrelevant in this case.
|
||||
factory BorderRadiusGeometry.circular(double radius) = BorderRadius.circular;
|
||||
|
||||
/// Creates a horizontally symmetrical border radius.
|
||||
///
|
||||
/// Utilizing the `left` and `right` properties will return a [BorderRadius],
|
||||
/// while `start` and `end` will yield a [BorderRadiusDirectional]. These
|
||||
/// properties cannot be used interchangeably.
|
||||
factory BorderRadiusGeometry.horizontal({
|
||||
Radius? left, // BorderRadius
|
||||
Radius? right, // BorderRadius
|
||||
Radius? start, // BorderRadiusDirectional
|
||||
Radius? end, // BorderRadiusDirectional
|
||||
}) {
|
||||
assert(
|
||||
(left == null && right == null) || (start == null && end == null),
|
||||
'The left and right values cannot be used in conjunction with start and end.',
|
||||
);
|
||||
|
||||
if (start != null || end != null) {
|
||||
return BorderRadiusDirectional.horizontal(
|
||||
start: start ?? Radius.zero,
|
||||
end: end ?? Radius.zero,
|
||||
);
|
||||
}
|
||||
return BorderRadius.horizontal(left: left ?? Radius.zero, right: right ?? Radius.zero);
|
||||
}
|
||||
|
||||
/// Creates a [BorderRadius] with only the given non-zero values.
|
||||
///
|
||||
/// The other corners will be right angles.
|
||||
const factory BorderRadiusGeometry.only({
|
||||
Radius topLeft,
|
||||
Radius topRight,
|
||||
Radius bottomLeft,
|
||||
Radius bottomRight,
|
||||
}) = BorderRadius.only;
|
||||
|
||||
/// Creates a [BorderRadiusDirectional] with only the given non-zero values.
|
||||
///
|
||||
/// The other corners will be right angles.
|
||||
const factory BorderRadiusGeometry.directional({
|
||||
Radius topStart,
|
||||
Radius topEnd,
|
||||
Radius bottomStart,
|
||||
Radius bottomEnd,
|
||||
}) = BorderRadiusDirectional.only;
|
||||
|
||||
/// Creates a vertically symmetric [BorderRadius] where the top and bottom
|
||||
/// sides of the rectangle have the same radii.
|
||||
const factory BorderRadiusGeometry.vertical({Radius top, Radius bottom}) = BorderRadius.vertical;
|
||||
|
||||
/// A [BorderRadius] with all zero radii.
|
||||
static const BorderRadiusGeometry zero = BorderRadius.zero;
|
||||
|
||||
Radius get _topLeft;
|
||||
Radius get _topRight;
|
||||
Radius get _bottomLeft;
|
||||
|
||||
@ -67,6 +67,48 @@ abstract class BoxBorder extends ShapeBorder {
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const BoxBorder();
|
||||
|
||||
/// Creates a [Border].
|
||||
///
|
||||
/// All the sides of the border default to [BorderSide.none].
|
||||
factory BoxBorder.fromLTRB({
|
||||
BorderSide top = BorderSide.none,
|
||||
BorderSide right = BorderSide.none,
|
||||
BorderSide bottom = BorderSide.none,
|
||||
BorderSide left = BorderSide.none,
|
||||
}) => Border(top: top, right: right, bottom: bottom, left: left);
|
||||
|
||||
/// A uniform [Border] with all sides the same color and width.
|
||||
///
|
||||
/// The sides default to black solid borders, one logical pixel wide.
|
||||
factory BoxBorder.all({Color color, double width, BorderStyle style, double strokeAlign}) =
|
||||
Border.all;
|
||||
|
||||
/// Creates a [Border] whose sides are all the same.
|
||||
const factory BoxBorder.fromBorderSide(BorderSide side) = Border.fromBorderSide;
|
||||
|
||||
/// Creates a [Border] with symmetrical vertical and horizontal sides.
|
||||
///
|
||||
/// The `vertical` argument applies to the [left] and [right] sides, and the
|
||||
/// `horizontal` argument applies to the [top] and [bottom] sides.
|
||||
///
|
||||
/// All arguments default to [BorderSide.none].
|
||||
const factory BoxBorder.symmetric({BorderSide vertical, BorderSide horizontal}) =
|
||||
Border.symmetric;
|
||||
|
||||
/// Creates a [BorderDirectional].
|
||||
///
|
||||
/// The [start] and [end] sides represent the horizontal sides; the start side
|
||||
/// is on the leading edge given the reading direction, and the end side is on
|
||||
/// the trailing edge. They are resolved during [paint].
|
||||
///
|
||||
/// All the sides of the border default to [BorderSide.none].
|
||||
factory BoxBorder.fromSTEB({
|
||||
BorderSide top = BorderSide.none,
|
||||
BorderSide start = BorderSide.none,
|
||||
BorderSide end = BorderSide.none,
|
||||
BorderSide bottom = BorderSide.none,
|
||||
}) => BorderDirectional(top: top, start: start, end: end, bottom: bottom);
|
||||
|
||||
/// The top side of this border.
|
||||
///
|
||||
/// This getter is available on both [Border] and [BorderDirectional]. If
|
||||
|
||||
@ -32,6 +32,46 @@ abstract class EdgeInsetsGeometry {
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const EdgeInsetsGeometry();
|
||||
|
||||
/// Creates insets where all the offsets are `value`.
|
||||
const factory EdgeInsetsGeometry.all(double value) = EdgeInsets.all;
|
||||
|
||||
/// Creates [EdgeInsets] with only the given values non-zero.
|
||||
const factory EdgeInsetsGeometry.only({double left, double right, double top, double bottom}) =
|
||||
EdgeInsets.only;
|
||||
|
||||
/// Creates [EdgeInsetsDirectional] with only the given values non-zero.
|
||||
const factory EdgeInsetsGeometry.directional({
|
||||
double start,
|
||||
double end,
|
||||
double top,
|
||||
double bottom,
|
||||
}) = EdgeInsetsDirectional.only;
|
||||
|
||||
/// Creates [EdgeInsets] with symmetrical vertical and horizontal offsets.
|
||||
const factory EdgeInsetsGeometry.symmetric({double vertical, double horizontal}) =
|
||||
EdgeInsets.symmetric;
|
||||
|
||||
/// Creates [EdgeInsets] from offsets from the left, top, right, and bottom.
|
||||
const factory EdgeInsetsGeometry.fromLTRB(double left, double top, double right, double bottom) =
|
||||
EdgeInsets.fromLTRB;
|
||||
|
||||
/// Creates [EdgeInsets] that match the given view padding.
|
||||
///
|
||||
/// If you need the current system padding or view insets in the context of a
|
||||
/// widget, consider using [MediaQuery.paddingOf] to obtain these values
|
||||
/// rather than using the value from a [FlutterView] directly, so that you get
|
||||
/// notified of changes.
|
||||
factory EdgeInsetsGeometry.fromViewPadding(ui.ViewPadding padding, double devicePixelRatio) =
|
||||
EdgeInsets.fromViewPadding;
|
||||
|
||||
/// Creates [EdgeInsetsDirectional] from offsets from the start, top, end, and
|
||||
/// bottom.
|
||||
const factory EdgeInsetsGeometry.fromSTEB(double start, double top, double end, double bottom) =
|
||||
EdgeInsetsDirectional.fromSTEB;
|
||||
|
||||
/// An [EdgeInsets] with zero offsets in each direction.
|
||||
static const EdgeInsetsGeometry zero = EdgeInsets.zero;
|
||||
|
||||
double get _bottom;
|
||||
double get _end;
|
||||
double get _left;
|
||||
|
||||
@ -333,4 +333,9 @@ void main() {
|
||||
'Alignment(1.0, 2.0) + AlignmentDirectional.centerEnd',
|
||||
);
|
||||
});
|
||||
|
||||
test('AlignmentGeometry factories', () {
|
||||
expect(const AlignmentGeometry.xy(4, 5), const Alignment(4, 5));
|
||||
expect(const AlignmentGeometry.directional(4, 5), const AlignmentDirectional(4, 5));
|
||||
});
|
||||
}
|
||||
|
||||
@ -621,4 +621,68 @@ void main() {
|
||||
borderRadius,
|
||||
);
|
||||
});
|
||||
|
||||
test('BorderRadiusGeometry factories', () {
|
||||
const Radius radius5 = Radius.circular(5);
|
||||
const Radius radius10 = Radius.circular(10);
|
||||
const Radius radius15 = Radius.circular(15);
|
||||
const Radius radius20 = Radius.circular(20);
|
||||
expect(const BorderRadiusGeometry.all(radius10), const BorderRadius.all(radius10));
|
||||
expect(BorderRadiusGeometry.circular(10), BorderRadius.circular(10));
|
||||
expect(
|
||||
BorderRadiusGeometry.horizontal(left: radius5, right: radius10),
|
||||
const BorderRadius.horizontal(left: radius5, right: radius10),
|
||||
);
|
||||
expect(
|
||||
BorderRadiusGeometry.horizontal(start: radius5, end: radius10),
|
||||
const BorderRadiusDirectional.horizontal(start: radius5, end: radius10),
|
||||
);
|
||||
expect(() {
|
||||
BorderRadiusGeometry.horizontal(start: radius5, left: radius10);
|
||||
}, throwsAssertionError);
|
||||
expect(() {
|
||||
BorderRadiusGeometry.horizontal(end: radius5, right: radius10);
|
||||
}, throwsAssertionError);
|
||||
expect(() {
|
||||
BorderRadiusGeometry.horizontal(
|
||||
end: radius5,
|
||||
right: radius10,
|
||||
start: radius5,
|
||||
left: radius10,
|
||||
);
|
||||
}, throwsAssertionError);
|
||||
expect(
|
||||
const BorderRadiusGeometry.only(
|
||||
topLeft: radius5,
|
||||
topRight: radius10,
|
||||
bottomLeft: radius15,
|
||||
bottomRight: radius20,
|
||||
),
|
||||
const BorderRadius.only(
|
||||
topLeft: radius5,
|
||||
topRight: radius10,
|
||||
bottomLeft: radius15,
|
||||
bottomRight: radius20,
|
||||
),
|
||||
);
|
||||
expect(
|
||||
const BorderRadiusGeometry.directional(
|
||||
topStart: radius5,
|
||||
topEnd: radius10,
|
||||
bottomStart: radius15,
|
||||
bottomEnd: radius20,
|
||||
),
|
||||
const BorderRadiusDirectional.only(
|
||||
topStart: radius5,
|
||||
topEnd: radius10,
|
||||
bottomStart: radius15,
|
||||
bottomEnd: radius20,
|
||||
),
|
||||
);
|
||||
expect(
|
||||
const BorderRadiusGeometry.vertical(top: radius5, bottom: radius10),
|
||||
const BorderRadius.vertical(top: radius5, bottom: radius10),
|
||||
);
|
||||
expect(BorderRadiusGeometry.zero, BorderRadius.zero);
|
||||
});
|
||||
}
|
||||
|
||||
@ -482,6 +482,27 @@ void main() {
|
||||
expect((ShapeWithoutInterior() + ShapeWithInterior()).preferPaintInterior, isFalse);
|
||||
expect((ShapeWithoutInterior() + ShapeWithoutInterior()).preferPaintInterior, isFalse);
|
||||
});
|
||||
|
||||
test('BoxBorder factories', () {
|
||||
const BorderSide side1 = BorderSide();
|
||||
const BorderSide side2 = BorderSide(width: 2);
|
||||
const BorderSide side3 = BorderSide(width: 3);
|
||||
const BorderSide side4 = BorderSide(width: 4);
|
||||
expect(
|
||||
BoxBorder.fromLTRB(left: side1, top: side2, right: side3, bottom: side4),
|
||||
const Border(left: side1, top: side2, right: side3, bottom: side4),
|
||||
);
|
||||
expect(BoxBorder.all(width: 4), Border.all(width: 4));
|
||||
expect(const BoxBorder.fromBorderSide(side3), const Border.fromBorderSide(side3));
|
||||
expect(
|
||||
const BoxBorder.symmetric(horizontal: side2, vertical: side3),
|
||||
const Border.symmetric(horizontal: side2, vertical: side3),
|
||||
);
|
||||
expect(
|
||||
BoxBorder.fromSTEB(start: side1, top: side2, end: side3, bottom: side4),
|
||||
const BorderDirectional(start: side1, top: side2, end: side3, bottom: side4),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
class ShapeWithInterior extends ShapeBorder {
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
@ -442,4 +444,33 @@ void main() {
|
||||
final EdgeInsetsDirectional copy = sourceEdgeInsets.copyWith(start: 5.0, top: 6.0);
|
||||
expect(copy, const EdgeInsetsDirectional.only(start: 5.0, top: 6.0, bottom: 3.0, end: 4.0));
|
||||
});
|
||||
|
||||
test('EdgeInsetsGeometry factories', () {
|
||||
expect(const EdgeInsetsGeometry.all(10), const EdgeInsets.all(10));
|
||||
expect(
|
||||
const EdgeInsetsGeometry.only(left: 10, top: 20, right: 30, bottom: 40),
|
||||
const EdgeInsets.only(left: 10, top: 20, right: 30, bottom: 40),
|
||||
);
|
||||
expect(
|
||||
const EdgeInsetsGeometry.directional(start: 10, top: 20, end: 30, bottom: 40),
|
||||
const EdgeInsetsDirectional.only(start: 10, top: 20, end: 30, bottom: 40),
|
||||
);
|
||||
expect(
|
||||
const EdgeInsetsGeometry.symmetric(horizontal: 10, vertical: 20),
|
||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
|
||||
);
|
||||
expect(
|
||||
const EdgeInsetsGeometry.fromLTRB(10, 20, 30, 40),
|
||||
const EdgeInsets.fromLTRB(10, 20, 30, 40),
|
||||
);
|
||||
expect(
|
||||
EdgeInsetsGeometry.fromViewPadding(ui.ViewPadding.zero, 10),
|
||||
EdgeInsets.fromViewPadding(ui.ViewPadding.zero, 10),
|
||||
);
|
||||
expect(
|
||||
const EdgeInsetsGeometry.fromSTEB(10, 20, 20, 40),
|
||||
const EdgeInsetsDirectional.fromSTEB(10, 20, 20, 40),
|
||||
);
|
||||
expect(EdgeInsetsGeometry.zero, EdgeInsets.zero);
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user