Add footer to CupertinoFormSection and fix CupertinoFormSection margins. (#72046)
This commit is contained in:
parent
781c9bcb4d
commit
bff0ec470a
@ -10,7 +10,7 @@ import 'theme.dart';
|
|||||||
|
|
||||||
// Content padding determined via SwiftUI's `Form` view in the iOS 14.2 SDK.
|
// Content padding determined via SwiftUI's `Form` view in the iOS 14.2 SDK.
|
||||||
const EdgeInsetsGeometry _kDefaultPadding =
|
const EdgeInsetsGeometry _kDefaultPadding =
|
||||||
EdgeInsetsDirectional.fromSTEB(16.0, 6.0, 6.0, 6.0);
|
EdgeInsetsDirectional.fromSTEB(20.0, 6.0, 6.0, 6.0);
|
||||||
|
|
||||||
/// An iOS-style form row.
|
/// An iOS-style form row.
|
||||||
///
|
///
|
||||||
@ -149,22 +149,7 @@ class CupertinoFormRow extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final CupertinoThemeData themeData = CupertinoTheme.of(context);
|
final TextStyle textStyle = CupertinoTheme.of(context).textTheme.textStyle;
|
||||||
final TextStyle textStyle = themeData.textTheme.textStyle;
|
|
||||||
|
|
||||||
final List<Widget> rowChildren = <Widget>[
|
|
||||||
if (prefix != null)
|
|
||||||
DefaultTextStyle(
|
|
||||||
style: textStyle,
|
|
||||||
child: prefix!,
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
child: Align(
|
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: padding ?? _kDefaultPadding,
|
padding: padding ?? _kDefaultPadding,
|
||||||
@ -172,7 +157,19 @@ class CupertinoFormRow extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: rowChildren,
|
children: <Widget>[
|
||||||
|
if (prefix != null)
|
||||||
|
DefaultTextStyle(
|
||||||
|
style: textStyle,
|
||||||
|
child: prefix!,
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
if (helper != null)
|
if (helper != null)
|
||||||
Align(
|
Align(
|
||||||
|
@ -9,12 +9,16 @@ import 'colors.dart';
|
|||||||
|
|
||||||
// Standard header margin, determined from SwiftUI's Forms in iOS 14.2 SDK.
|
// Standard header margin, determined from SwiftUI's Forms in iOS 14.2 SDK.
|
||||||
const EdgeInsetsDirectional _kDefaultHeaderMargin =
|
const EdgeInsetsDirectional _kDefaultHeaderMargin =
|
||||||
EdgeInsetsDirectional.fromSTEB(16.5, 16.0, 16.5, 10.0);
|
EdgeInsetsDirectional.fromSTEB(20.0, 16.0, 20.0, 10.0);
|
||||||
|
|
||||||
|
// Standard footer margin, determined from SwiftUI's Forms in iOS 14.2 SDK.
|
||||||
|
const EdgeInsetsDirectional _kDefaultFooterMargin =
|
||||||
|
EdgeInsetsDirectional.fromSTEB(20.0, 0.0, 20.0, 10.0);
|
||||||
|
|
||||||
// Used for iOS "Inset Grouped" margin, determined from SwiftUI's Forms in
|
// Used for iOS "Inset Grouped" margin, determined from SwiftUI's Forms in
|
||||||
// iOS 14.2 SDK.
|
// iOS 14.2 SDK.
|
||||||
const EdgeInsetsDirectional _kDefaultInsetGroupedRowsMargin =
|
const EdgeInsetsDirectional _kDefaultInsetGroupedRowsMargin =
|
||||||
EdgeInsetsDirectional.fromSTEB(16.5, 0.0, 16.5, 16.5);
|
EdgeInsetsDirectional.fromSTEB(20.0, 0.0, 20.0, 10.0);
|
||||||
|
|
||||||
// Used for iOS "Inset Grouped" border radius, estimated from SwiftUI's Forms in
|
// Used for iOS "Inset Grouped" border radius, estimated from SwiftUI's Forms in
|
||||||
// iOS 14.2 SDK.
|
// iOS 14.2 SDK.
|
||||||
@ -39,6 +43,9 @@ enum _CupertinoFormSectionType { base, insetGrouped }
|
|||||||
/// The [header] parameter sets the form section header. The section header lies
|
/// The [header] parameter sets the form section header. The section header lies
|
||||||
/// above the [children] rows, with margins that match the iOS style.
|
/// above the [children] rows, with margins that match the iOS style.
|
||||||
///
|
///
|
||||||
|
/// The [footer] parameter sets the form section footer. The section footer
|
||||||
|
/// lies below the [children] rows.
|
||||||
|
///
|
||||||
/// The [children] parameter is required and sets the list of rows shown in
|
/// The [children] parameter is required and sets the list of rows shown in
|
||||||
/// the section. The [children] parameter takes a list, as opposed to a more
|
/// the section. The [children] parameter takes a list, as opposed to a more
|
||||||
/// efficient builder function that lazy builds, because forms are intended to
|
/// efficient builder function that lazy builds, because forms are intended to
|
||||||
@ -69,6 +76,9 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
/// The [header] parameter sets the form section header. The section header
|
/// The [header] parameter sets the form section header. The section header
|
||||||
/// lies above the [children] rows, with margins that match the iOS style.
|
/// lies above the [children] rows, with margins that match the iOS style.
|
||||||
///
|
///
|
||||||
|
/// The [footer] parameter sets the form section footer. The section footer
|
||||||
|
/// lies below the [children] rows.
|
||||||
|
///
|
||||||
/// The [children] parameter is required and sets the list of rows shown in
|
/// The [children] parameter is required and sets the list of rows shown in
|
||||||
/// the section. The [children] parameter takes a list, as opposed to a more
|
/// the section. The [children] parameter takes a list, as opposed to a more
|
||||||
/// efficient builder function that lazy builds, because forms are intended to
|
/// efficient builder function that lazy builds, because forms are intended to
|
||||||
@ -93,6 +103,7 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
Key? key,
|
Key? key,
|
||||||
required this.children,
|
required this.children,
|
||||||
this.header,
|
this.header,
|
||||||
|
this.footer,
|
||||||
this.margin = EdgeInsets.zero,
|
this.margin = EdgeInsets.zero,
|
||||||
this.backgroundColor = CupertinoColors.systemGroupedBackground,
|
this.backgroundColor = CupertinoColors.systemGroupedBackground,
|
||||||
this.decoration,
|
this.decoration,
|
||||||
@ -111,6 +122,9 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
/// The [header] parameter sets the form section header. The section header
|
/// The [header] parameter sets the form section header. The section header
|
||||||
/// lies above the [children] rows, with margins that match the iOS style.
|
/// lies above the [children] rows, with margins that match the iOS style.
|
||||||
///
|
///
|
||||||
|
/// The [footer] parameter sets the form section footer. The section footer
|
||||||
|
/// lies below the [children] rows.
|
||||||
|
///
|
||||||
/// The [children] parameter is required and sets the list of rows shown in
|
/// The [children] parameter is required and sets the list of rows shown in
|
||||||
/// the section. The [children] parameter takes a list, as opposed to a more
|
/// the section. The [children] parameter takes a list, as opposed to a more
|
||||||
/// efficient builder function that lazy builds, because forms are intended to
|
/// efficient builder function that lazy builds, because forms are intended to
|
||||||
@ -136,6 +150,7 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
Key? key,
|
Key? key,
|
||||||
required this.children,
|
required this.children,
|
||||||
this.header,
|
this.header,
|
||||||
|
this.footer,
|
||||||
this.margin = _kDefaultInsetGroupedRowsMargin,
|
this.margin = _kDefaultInsetGroupedRowsMargin,
|
||||||
this.backgroundColor = CupertinoColors.systemGroupedBackground,
|
this.backgroundColor = CupertinoColors.systemGroupedBackground,
|
||||||
this.decoration,
|
this.decoration,
|
||||||
@ -150,6 +165,10 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
/// [children] rows.
|
/// [children] rows.
|
||||||
final Widget? header;
|
final Widget? header;
|
||||||
|
|
||||||
|
/// Sets the form section footer. The section footer lies below the
|
||||||
|
/// [children] rows.
|
||||||
|
final Widget? footer;
|
||||||
|
|
||||||
/// Margin around the content area of the section encapsulating [children].
|
/// Margin around the content area of the section encapsulating [children].
|
||||||
///
|
///
|
||||||
/// Defaults to zero padding if constructed with standard
|
/// Defaults to zero padding if constructed with standard
|
||||||
@ -228,6 +247,16 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
childrenWithDividers.add(longDivider);
|
childrenWithDividers.add(longDivider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final BorderRadius childrenGroupBorderRadius;
|
||||||
|
switch (_type) {
|
||||||
|
case _CupertinoFormSectionType.insetGrouped:
|
||||||
|
childrenGroupBorderRadius = _kDefaultInsetGroupedBorderRadius;
|
||||||
|
break;
|
||||||
|
case _CupertinoFormSectionType.base:
|
||||||
|
childrenGroupBorderRadius = BorderRadius.zero;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Refactored the decorate children group in one place to avoid repeating it
|
// Refactored the decorate children group in one place to avoid repeating it
|
||||||
// twice down bellow in the returned widget.
|
// twice down bellow in the returned widget.
|
||||||
final DecoratedBox decoratedChildrenGroup = DecoratedBox(
|
final DecoratedBox decoratedChildrenGroup = DecoratedBox(
|
||||||
@ -237,7 +266,7 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
decoration?.color ??
|
decoration?.color ??
|
||||||
CupertinoColors.secondarySystemGroupedBackground,
|
CupertinoColors.secondarySystemGroupedBackground,
|
||||||
context),
|
context),
|
||||||
borderRadius: _kDefaultInsetGroupedBorderRadius,
|
borderRadius: childrenGroupBorderRadius,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: childrenWithDividers,
|
children: childrenWithDividers,
|
||||||
@ -250,31 +279,43 @@ class CupertinoFormSection extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Align(
|
if (header != null)
|
||||||
alignment: AlignmentDirectional.centerStart,
|
Align(
|
||||||
child: header == null
|
alignment: AlignmentDirectional.centerStart,
|
||||||
? null
|
child: DefaultTextStyle(
|
||||||
: DefaultTextStyle(
|
style: TextStyle(
|
||||||
style: TextStyle(
|
fontSize: 13.0,
|
||||||
fontSize: 13.5,
|
color: CupertinoColors.secondaryLabel.resolveFrom(context),
|
||||||
color:
|
),
|
||||||
CupertinoColors.secondaryLabel.resolveFrom(context),
|
child: Padding(
|
||||||
),
|
padding: _kDefaultHeaderMargin,
|
||||||
child: Padding(
|
child: header!,
|
||||||
padding: _kDefaultHeaderMargin,
|
),
|
||||||
child: header!,
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: margin,
|
padding: margin,
|
||||||
child: clipBehavior == Clip.none
|
child: clipBehavior == Clip.none
|
||||||
? decoratedChildrenGroup
|
? decoratedChildrenGroup
|
||||||
: ClipRRect(
|
: ClipRRect(
|
||||||
borderRadius: _kDefaultInsetGroupedBorderRadius,
|
borderRadius: childrenGroupBorderRadius,
|
||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
child: decoratedChildrenGroup),
|
child: decoratedChildrenGroup),
|
||||||
),
|
),
|
||||||
|
if (footer != null)
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: DefaultTextStyle(
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13.0,
|
||||||
|
color: CupertinoColors.secondaryLabel.resolveFrom(context),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: _kDefaultFooterMargin,
|
||||||
|
child: footer!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -8,20 +8,33 @@ import 'package:flutter/rendering.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('Shows header', (WidgetTester tester) async {
|
testWidgets('Shows header', (WidgetTester tester) async {
|
||||||
const Widget header = Text('Enter Value');
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
CupertinoApp(
|
||||||
home: Center(
|
home: Center(
|
||||||
child: CupertinoFormSection(
|
child: CupertinoFormSection(
|
||||||
header: header,
|
header: const Text('Header'),
|
||||||
children: <Widget>[CupertinoTextFormFieldRow()],
|
children: <Widget>[CupertinoTextFormFieldRow()],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(header, tester.widget(find.byType(Text)));
|
expect(find.text('Header'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Shows footer', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoFormSection(
|
||||||
|
footer: const Text('Footer'),
|
||||||
|
children: <Widget>[CupertinoTextFormFieldRow()],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.text('Footer'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Shows long dividers in edge-to-edge section part 1',
|
testWidgets('Shows long dividers in edge-to-edge section part 1',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user