form_row.dart 6.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
// 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/widgets.dart';

import 'colors.dart';
import 'theme.dart';

// Content padding determined via SwiftUI's `Form` view in the iOS 14.2 SDK.
const EdgeInsetsGeometry _kDefaultPadding =
12
    EdgeInsetsDirectional.fromSTEB(20.0, 6.0, 6.0, 6.0);
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

/// An iOS-style form row.
///
/// Creates an iOS-style split form row with a standard prefix and child widget.
/// Also provides a space for error and helper widgets that appear underneath.
///
/// The [child] parameter is required. This widget is displayed at the end of
/// the row.
///
/// The [prefix] parameter is optional and is displayed at the start of the
/// row. Standard iOS guidelines encourage passing a [Text] widget to [prefix]
/// to detail the nature of the row's [child] widget.
///
/// The [padding] parameter is used to pad the contents of the row. It defaults
/// to the standard iOS padding. If no edge insets are intended, explicitly pass
/// [EdgeInsets.zero] to [padding].
///
/// The [helper] and [error] parameters are both optional widgets targeted at
/// displaying more information about the row. Both widgets are placed
/// underneath the [prefix] and [child], and will expand the row's height to
33
/// accommodate for their presence. When a [Text] is given to [error], it will
34 35 36
/// be shown in [CupertinoColors.destructiveRed] coloring and
/// medium-weighted font.
///
37 38 39
/// {@tool dartpad}
/// Creates a [CupertinoFormSection] containing a [CupertinoFormRow] with [prefix],
/// [child], [helper] and [error] specified.
40
///
41
/// ** See code in examples/api/lib/cupertino/form_row/cupertino_form_row.0.dart **
42
/// {@end-tool}
43
///
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
class CupertinoFormRow extends StatelessWidget {
  /// Creates an iOS-style split form row with a standard prefix and child widget.
  /// Also provides a space for error and helper widgets that appear underneath.
  ///
  /// The [child] parameter is required. This widget is displayed at the end of
  /// the row.
  ///
  /// The [prefix] parameter is optional and is displayed at the start of the
  /// row. Standard iOS guidelines encourage passing a [Text] widget to [prefix]
  /// to detail the nature of the row's [child] widget.
  ///
  /// The [padding] parameter is used to pad the contents of the row. It defaults
  /// to the standard iOS padding. If no edge insets are intended, explicitly
  /// pass [EdgeInsets.zero] to [padding].
  ///
  /// The [helper] and [error] parameters are both optional widgets targeted at
  /// displaying more information about the row. Both widgets are placed
  /// underneath the [prefix] and [child], and will expand the row's height to
62
  /// accommodate for their presence. When a [Text] is given to [error], it will
63 64 65
  /// be shown in [CupertinoColors.destructiveRed] coloring and
  /// medium-weighted font.
  const CupertinoFormRow({
66
    super.key,
67 68 69 70 71
    required this.child,
    this.prefix,
    this.padding,
    this.helper,
    this.error,
72
  });
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

  /// A widget that is displayed at the start of the row.
  ///
  /// The [prefix] parameter is displayed at the start of the row. Standard iOS
  /// guidelines encourage passing a [Text] widget to [prefix] to detail the
  /// nature of the row's [child] widget. If null, the [child] widget will take
  /// up all horizontal space in the row.
  final Widget? prefix;

  /// Content padding for the row.
  ///
  /// Defaults to the standard iOS padding for form rows. If no edge insets are
  /// intended, explicitly pass [EdgeInsets.zero] to [padding].
  final EdgeInsetsGeometry? padding;

  /// A widget that is displayed underneath the [prefix] and [child] widgets.
  ///
  /// The [helper] appears in primary label coloring, and is meant to inform the
  /// user about interaction with the child widget. The row becomes taller in
  /// order to display the [helper] widget underneath [prefix] and [child]. If
  /// null, the row is shorter.
  final Widget? helper;

  /// A widget that is displayed underneath the [prefix] and [child] widgets.
  ///
  /// The [error] widget is primarily used to inform users of input errors. When
  /// a [Text] is given to [error], it will be shown in
  /// [CupertinoColors.destructiveRed] coloring and medium-weighted font. The
  /// row becomes taller in order to display the [helper] widget underneath
  /// [prefix] and [child]. If null, the row is shorter.
  final Widget? error;

  /// Child widget.
  ///
  /// The [child] widget is primarily used for input. It end-aligned and
  /// horizontally flexible, taking up the entire space trailing past the
  /// [prefix] widget.
  final Widget child;

  @override
  Widget build(BuildContext context) {
114 115 116 117
    final CupertinoThemeData theme = CupertinoTheme.of(context);
    final TextStyle textStyle = theme.textTheme.textStyle.copyWith(
      color: CupertinoDynamicColor.maybeResolve(theme.textTheme.textStyle.color, context)
    );
118 119 120 121 122 123 124

    return Padding(
      padding: padding ?? _kDefaultPadding,
      child: Column(
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
125 126 127 128 129 130 131 132 133 134 135 136 137
            children: <Widget>[
              if (prefix != null)
                DefaultTextStyle(
                  style: textStyle,
                  child: prefix!,
                ),
              Flexible(
                child: Align(
                  alignment: AlignmentDirectional.centerEnd,
                  child: child,
                ),
              ),
            ],
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
          ),
          if (helper != null)
            Align(
              alignment: AlignmentDirectional.centerStart,
              child: DefaultTextStyle(
                style: textStyle,
                child: helper!,
              ),
            ),
          if (error != null)
            Align(
              alignment: AlignmentDirectional.centerStart,
              child: DefaultTextStyle(
                style: const TextStyle(
                  color: CupertinoColors.destructiveRed,
                  fontWeight: FontWeight.w500,
                ),
                child: error!,
              ),
            ),
        ],
      ),
    );
  }
}