Unverified Commit bff0ec47 authored by Daniel Edrisian's avatar Daniel Edrisian Committed by GitHub

Add footer to CupertinoFormSection and fix CupertinoFormSection margins. (#72046)

parent 781c9bcb
...@@ -10,7 +10,7 @@ import 'theme.dart'; ...@@ -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 { ...@@ -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 { ...@@ -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'; ...@@ -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 } ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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'; ...@@ -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(
CupertinoApp(
home: Center(
child: CupertinoFormSection(
header: const Text('Header'),
children: <Widget>[CupertinoTextFormFieldRow()],
),
),
),
);
expect(find.text('Header'), findsOneWidget);
});
testWidgets('Shows footer', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
home: Center( home: Center(
child: CupertinoFormSection( child: CupertinoFormSection(
header: header, footer: const Text('Footer'),
children: <Widget>[CupertinoTextFormFieldRow()], children: <Widget>[CupertinoTextFormFieldRow()],
), ),
), ),
), ),
); );
expect(header, tester.widget(find.byType(Text))); 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',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment