Buttons & Dialogs

Technology for ecology

Buttons & Dialogs

ElevatedButton

Flutter elevated button

Simple dialogs using:

  • 1 centered single button (width adapted to text)
  • 2 aligned and expanded buttons (Cancel & Confirm).
import 'package:flutter/material.dart';

class ButtonElevated extends StatefulWidget {
  const ButtonElevated({Key? key}) : super(key: key);

  @override
  _ButtonElevatedState createState() => _ButtonElevatedState();
}

class _ButtonElevatedState extends State<ButtonElevated> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Elevated Buttons")),
      body: Container(
        padding: const EdgeInsets.all(20),
        alignment: Alignment.center,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            oneSingleButton(context),
            const SizedBox(height: 100),
            twoAlignedButtons(context),
            const SizedBox(height: 150),
          ],
        )
      )
    );
  }

  Widget oneSingleButton(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        print("Single button pressed");
      },
      style: ElevatedButton.styleFrom(
          backgroundColor: Colors.blue,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
      ),
      child: const Text("Single button")
    );
  }


  Widget twoAlignedButtons(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Expanded(child: cancelButton(context)),
        const VerticalDivider(width: 20),
        Expanded(child: confirmButton(context)),
      ],
    );
  }

  Widget cancelButton(BuildContext context) {
    return ElevatedButton(
        onPressed: () {
          print("Cancel button pressed");
          Navigator.pop(context);
        },
        style: ElevatedButton.styleFrom(
            foregroundColor: Colors.blue,
            backgroundColor: Colors.white,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
        ),
        child: const Text("Cancel")
    );
  }

  Widget confirmButton(BuildContext context) {
    return ElevatedButton(
        onPressed: () {
          print("Confirm button pressed");
        },
        style: ElevatedButton.styleFrom(
            foregroundColor: Colors.white,
            backgroundColor: Colors.blue,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
        ),
        child: const Text("Confirm")
    );
  }

}

AlertDialog

AlertDialog

Shows a simple pop-up dialog fully customizable with 2 buttons

import 'package:flutter/material.dart';


class DialogAlert extends StatefulWidget {
  const DialogAlert({Key? key}) : super(key: key);

  @override
  _DialogAlertState createState() => _DialogAlertState();
}

class _DialogAlertState extends State<DialogAlert> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("AlertDialog")),
        body: Container(
            padding: const EdgeInsets.all(20),
            alignment: Alignment.center,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                oneSingleButton(context),
              ],
            )
        )
    );
  }

  /// **********************************************************************
  /// This button just for calling the AlertDialog
  /// **********************************************************************
  Widget oneSingleButton(BuildContext context) {
    return ElevatedButton(
        onPressed: () {
          confirmPhoto(context);
        },
        style: ElevatedButton.styleFrom(
            backgroundColor: Colors.blue,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
        ),
        child: const Text("Tap here")
    );
  }

  /// **********************************************************************
  /// Pops up the AlertDialog
  /// **********************************************************************
  void confirmPhoto(context) {
    showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: const Text("Do you like the photo ?"),
            titleTextStyle: const TextStyle(
                fontSize: 20,
                color: Colors.black),
            shape: const RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(15))
            ),
            content: const Text("Please answer Yes or No"),
            actionsPadding: const EdgeInsets.symmetric(horizontal: 28),
            actions: [

              // Button No
              ElevatedButton(
                style: ElevatedButton.styleFrom(
                    foregroundColor: Colors.blue,
                    backgroundColor: Colors.white,
                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
                ),
                child: Text("No",
                    style: TextStyle(color: Theme.of(context).colorScheme.secondary)),
                onPressed: () {
                  print("Answer is No");
                  Navigator.pop(context);
                },
              ),

              // Button Yes
              ElevatedButton(
                style: ElevatedButton.styleFrom(
                    foregroundColor: Colors.white,
                    backgroundColor: Colors.blue,
                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),
                    )
                ),
                child: Text("Yes",
                    style: TextStyle(color: Theme.of(context).bottomAppBarColor)),
                onPressed: () {
                  print("Answer is Yes");
                  Navigator.pop(context);
                },
              ),
            ],
          );
        }
    );

  }
}

CupertinoAlertDialog

CupertinoDialog

Shows a simple Cupertino style pop-up dialog fully customizable with 2 buttons

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class ShowDialogCupertino extends StatefulWidget {
  const ShowDialogCupertino({Key? key}) : super(key: key);

  @override
  _ShowDialogCupertinoState createState() => _ShowDialogCupertinoState();
}

class _ShowDialogCupertinoState extends State<ShowDialogCupertino> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("CupertinoAlertDialog")),
        body: Container(
            padding: const EdgeInsets.all(20),
            alignment: Alignment.center,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                oneSingleButton(context),
              ],
            )
        )
    );
  }

  /// **********************************************************************
  /// This button just for calling the AlertDialog
  /// **********************************************************************
  Widget oneSingleButton(BuildContext context) {
    return ElevatedButton(
        onPressed: () {
          confirmPhoto(context);
        },
        style: ElevatedButton.styleFrom(
            backgroundColor: Colors.blue,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
        ),
        child: const Text("Tap here")
    );
  }

  /// **********************************************************************
  /// Cupertino style dialog
  /// **********************************************************************
  Future<void> confirmPhoto(BuildContext context) async {

    showCupertinoDialog(
        context: context,
        builder: (builder) => CupertinoAlertDialog(
          title: const Text("Delete photo ?"),
          content: const Text("Please confirm"),
          actions: [
            CupertinoDialogAction(
                child: const Text("Cancel"),
                onPressed: () {
                  print("Canceled");
                  Navigator.of(context).pop(); }
            ),
            CupertinoDialogAction(
                child: const Text("Confirm"),
                onPressed: (){
                  print("Confirmed");
                  Navigator.of(context).pop();
                }
            )
          ],
        )
    );
  }
}

Simple TextField

Simple TextField

Simple TextField allowing to capture free text up to 60 characters max over 2 lines. A button (cross) is displayed as a suffix icon to clear the input data. The text capture is completed when Enter key is pressed.

import 'package:flutter/material.dart';


class ShowTextField extends StatefulWidget {
  const ShowTextField({Key? key}) : super(key: key);

  @override
  _ShowTextFieldState createState() => _ShowTextFieldState();
}

class _ShowTextFieldState extends State<ShowTextField> {

  // Controller for text editing
  final TextEditingController _controller = TextEditingController();
  final _focusComments = FocusNode();



  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("Simple Text Field")),
        body: Container(
            padding: const EdgeInsets.all(20),
            alignment: Alignment.center,
            child: Center(
              child: DisplayTextField(context)
            )
        )
    );
  }


  Widget DisplayTextField(BuildContext context) {
    return Expanded(
      child: TextField(
        controller: _controller,
        focusNode: _focusComments,
        textCapitalization: TextCapitalization.sentences,
        maxLength: 100,
        maxLines: 2,
        keyboardType: TextInputType.text,
        textInputAction: TextInputAction.done,
        //maxLengthEnforcement: MaxLengthEnforcement.enforced,
        decoration: InputDecoration(
            border:  const OutlineInputBorder(
                borderRadius: BorderRadius.all(Radius.circular(30))
            ),
            labelText: "Enter your comments",

            suffixIcon: IconButton(
                onPressed: _controller.clear,
                icon: const Icon(Icons.clear)
            )
        ),
        onSubmitted: (value) => print("Captured text = $value"),
      ),
    );
  }
}

Form

TextFormField

Typical login form to capture email and password with TextFormField widgets and one ElevatedButton to confirm inputs. Password field can be obscured or displayed in clear. When Confirm is hit, email and password are then validated against criteria.

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

class ShowForm extends StatefulWidget {
  const ShowForm({Key? key}) : super(key: key);

  @override
  _ShowFormState createState() => _ShowFormState();
}

class _ShowFormState extends State<ShowForm> {

  // Controllers for text editing
  final TextEditingController _emailTextController = TextEditingController();
  final _focusEmail = FocusNode();
  final TextEditingController _passwordTextController = TextEditingController();
  final _focusPassword = FocusNode();

  bool _obscurePassword = true;

  // Form management key
  static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();


  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("Form")),
        body: Container(
            padding: const EdgeInsets.all(20),
            alignment: Alignment.center,
            child: Center(
                child: loginForm(context)
            )
        )
    );
  }

  /// **********************************************************************
  /// Sign in form with email/password: 2 TextFormFields and 1 ElevatedButton
  /// **********************************************************************
  Widget loginForm(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,

        children: <Widget>[

          emailInput(context),

          const SizedBox(height: 8.0),

          passwordInput(context),

          const SizedBox(height: 25.0),

          confirmButton(context)

        ],
      ),
    );
  }

  /// **********************************************************************
  /// Email input capture with TextFormField
  /// **********************************************************************
  Widget emailInput(BuildContext context) {
    return TextFormField(
      controller: _emailTextController,
      focusNode: _focusEmail,
      validator: (value) => _validateEmail(context: context, email: value!),
      decoration: InputDecoration(
        hintText: "Email",
        border: const OutlineInputBorder(
            borderRadius: BorderRadius.all(Radius.circular(20),
            )),
        errorBorder: UnderlineInputBorder(
          borderRadius: BorderRadius.circular(6.0),
          borderSide: const BorderSide(
            color: Colors.red,
          ),
        ),
      ),
    );
  }

  /// **********************************************************************
  /// Password input capture with TextFormField
  /// **********************************************************************
  Widget passwordInput(BuildContext context) {
    return TextFormField(
      controller: _passwordTextController,
      focusNode: _focusPassword,
      obscureText: _obscurePassword,
      validator: (value) => _validatePassword(context: context, password: value!),
      decoration: InputDecoration(
          hintText: "Password",
          border: const OutlineInputBorder(
              borderRadius: BorderRadius.all(Radius.circular(20),
              )
          ),
          errorBorder: UnderlineInputBorder(
            borderRadius: BorderRadius.circular(6.0),
            borderSide: const BorderSide(
              color: Colors.red,
            ),
          ),
          suffixIcon: IconButton(
            onPressed: () {
              setState(() {
                _obscurePassword = !_obscurePassword;
              });
            },
            icon: (_obscurePassword)
                ? const Icon(CupertinoIcons.eye_slash_fill)
                : const Icon(CupertinoIcons.eye_fill),
          )
      ),
    );
  }

  /// **********************************************************************
  /// Button to confirm the login details
  /// **********************************************************************
  Widget confirmButton(BuildContext context) {
    return Row(
      children: [
        Expanded(
            child: ElevatedButton(
              onPressed: () => _login(),
              style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.blue,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0))
              ),

              child: Text("Confirm"),
              ),
            )
        ]
    );
  }

/// **********************************************************************
/// Called when confirmButton is pressed
/// **********************************************************************
Future<void> _login() async {
  _focusEmail.unfocus();
  _focusPassword.unfocus();

  // Validation of all inputs
  if (_formKey.currentState!.validate()) {
    print("Login with email = ${_emailTextController.text} "
        "and password = ${_passwordTextController.text}");
  }
}

  /// **********************************************************************
  /// Checks whether the email address field is empty
  /// and validate format using a regular expression
  /// **********************************************************************
  static String? _validateEmail({required BuildContext context, required String email}) {
    RegExp emailRegExp = RegExp(
        r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$");

    if (email.isEmpty) {
      return "Please enter a valid email address";
    } else if (!emailRegExp.hasMatch(email)) {
      return "Please enter a valid email address";
    }

    return null;
  }

  /// **********************************************************************
  /// Checks whether the password field is empty
  /// and verify that the length is longer than six characters
  /// **********************************************************************
  static String? _validatePassword({required BuildContext context, required String password}) {

    if (password.isEmpty) {
      return "Password must contain at least 6 characters";
    } else if (password.length < 6) {
      return "Password must contain at least 6 characters";
    }

    return null;
  }
}

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *