// 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 = EdgeInsetsDirectional.fromSTEB(20.0, 6.0, 6.0, 6.0); /// 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 /// accommodate for their presence. When a [Text] is given to [error], it will /// be shown in [CupertinoColors.destructiveRed] coloring and /// medium-weighted font. /// /// {@tool snippet} /// /// Creates a [CupertinoFormSection] containing a [CupertinoFormRow] with the /// [prefix], [child], [helper] and [error] widgets. /// /// ```dart /// class FlutterDemo extends StatefulWidget { /// const FlutterDemo({Key? key}) : super(key: key); /// /// @override /// State<FlutterDemo> createState() => _FlutterDemoState(); /// } /// /// class _FlutterDemoState extends State<FlutterDemo> { /// bool toggleValue = false; /// /// @override /// Widget build(BuildContext context) { /// return CupertinoPageScaffold( /// child: Center( /// child: CupertinoFormSection( /// header: const Text('SECTION 1'), /// children: <Widget>[ /// CupertinoFormRow( /// child: CupertinoSwitch( /// value: toggleValue, /// onChanged: (bool value) { /// setState(() { /// toggleValue = value; /// }); /// }, /// ), /// prefix: const Text('Toggle'), /// helper: const Text('Use your instincts'), /// error: toggleValue ? const Text('Cannot be true') : null, /// ), /// ], /// ), /// ), /// ); /// } /// } /// ``` /// {@end-tool} 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 /// accommodate for their presence. When a [Text] is given to [error], it will /// be shown in [CupertinoColors.destructiveRed] coloring and /// medium-weighted font. const CupertinoFormRow({ Key? key, required this.child, this.prefix, this.padding, this.helper, this.error, }) : super(key: key); /// 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) { final TextStyle textStyle = CupertinoTheme.of(context).textTheme.textStyle; return Padding( padding: padding ?? _kDefaultPadding, child: Column( children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ if (prefix != null) DefaultTextStyle( style: textStyle, child: prefix!, ), Flexible( child: Align( alignment: AlignmentDirectional.centerEnd, child: child, ), ), ], ), 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!, ), ), ], ), ); } }