1

I have this design that I'm creating on Flutter:

enter image description here

Here is what I managed to do so far:

enter image description here

I'll provided you my code and I ll explain it and finally I'll try to explain the error that I'm having. First here is my code:

class CheckoutPage extends StatefulWidget {
  const CheckoutPage({super.key});

  @override
  State<CheckoutPage> createState() => _CheckoutPageState();
}

class _CheckoutPageState extends State<CheckoutPage>
    with TickerProviderStateMixin {
  Map<String, bool> isActive = {
    'Quantity': true,
    'Payment': false,
    'Review': false,
  };
  Map<String, bool> isDone = {
    'Quantity': false,
    'Payment': false,
    'Review': false,
  };
  @override
  Widget build(BuildContext context) {
    order = ModalRoute.of(context)!.settings.arguments as Order;
    final PageController pageViewController = PageController();
    final double height = MediaQuery.of(context).size.height;
    final GlobalKey<FormState> formKey = GlobalKey<FormState>();
    final TextEditingController nameController = TextEditingController();
    final TextEditingController phoneNumberController = TextEditingController();
    final TextEditingController addressController = TextEditingController();

    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Stack(
        children: [
          Column(
            children: [
              SizedBox(
                height: height * 0.16,
                child: PageViewIndicator(isActive: isActive, isDone: isDone),
              ),
              SizedBox(
                height: height * 0.84,
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 8,
                    vertical: 18,
                  ),
                  child: PageView(
                    controller: pageViewController,
                    children: [
                      QuantityStepWidget(
                        formKey: formKey,
                        addressController: addressController,
                        nameController: nameController,
                        phoneNumberController: phoneNumberController,
                      ),
                      const PaymentStepWidget(),
                      const ReviewStepWidget(),
                    ],
                  ),
                ),
              ),
            ],
          ),
          const BackButtonWidget(),
        ],
      ),
    );
  }
}

This code is mainly composed of a Scaffold, it's child is a Stack that stacks a back button (BackButton) on tap of a Column. This column has two containers SizedBox; the first one takes 16% of the height of the screen, and the second one takes 84% which makes a total of 100%. Inside the first SizedBox I defined a PageViewIndicator widget which is a Container that holds a Row that holds 3 HeadingPageViewItemWidget like this:


class PageViewIndicator extends StatelessWidget {
  final Map<String, bool> isActive;
  final Map<String, bool> isDone;
  const PageViewIndicator({
    super.key,
    required this.isActive,
    required this.isDone,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        border: Border(
          bottom: BorderSide(color: AppColors.borderColor),
        ),
      ),
      child: Padding(
        padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 20),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            HeadingPageViewItemWidget(
              number: '1',
              title: 'Quantity',
              isActive: isActive['Quantity']!,
              isDone: isDone['Quantity']!,
            ),
            HeadingPageViewItemWidget(
              number: '2',
              title: 'Payment',
              isActive: isActive['Payment']!,
              isDone: isDone['Payment']!,
            ),
            HeadingPageViewItemWidget(
              number: '3',
              title: 'Review',
              isActive: isActive['Review']!,
              isDone: isDone['Review']!,
            ),
          ],
        ),
      ),
    );
  }
}

The HeadingPageViewItemWidget is another Row that holds a CircleAvatar and a Text widget, like this:


class HeadingPageViewItemWidget extends StatelessWidget {
  final String number;
  final String title;
  final bool isDone;
  final bool isActive;
  const HeadingPageViewItemWidget({
    Key? key,
    required this.number,
    required this.title,
    this.isDone = false,
    this.isActive = false,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 100,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          CircleAvatar(
            backgroundColor: _getColor(isDone: isDone, isActive: isActive),
            radius: 15,
            child: _getIconOrNumber(isDone),
          ),
          SizedBox(
            width: 60,
            child: Text(title, style: kCaption0),
          ),
        ],
      ),
    );
  }
}

Inside the second SizedBox I have defined a PageView that has 3 children, QuantityStepWidget, PaymentStepWidget and ReviewStepWidget, these last two are just PlaceHolders for the moment. The QuantityStepWidget is defined like this:


class QuantityStepWidget extends StatelessWidget {
  final GlobalKey<FormState> formKey;
  final TextEditingController nameController;
  final TextEditingController phoneNumberController;
  final TextEditingController addressController;
  const QuantityStepWidget(
      {super.key,
      required this.formKey,
      required this.nameController,
      required this.phoneNumberController,
      required this.addressController});

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: SizedBox(
        height: MediaQuery.of(context).size.height * 0.8,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Flexible(
              fit: FlexFit.loose,
              child: SizedBox(
                  height: MediaQuery.of(context).size.height * 0.05,
                  child: const TitleWidget(title: 'Quantity')),
            ),
            Flexible(
              flex: 3,
              fit: FlexFit.loose,
              child: SizedBox(
                height: MediaQuery.of(context).size.height * 0.35,
                width: double.infinity,
                child: MedicationCheckoutQuantityWidget(order: order),
              ),
            ),
            Flexible(
              flex: 3,
              fit: FlexFit.loose,
              child: SizedBox(
                height: MediaQuery.of(context).size.height * 0.4,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'Confirm your information',
                      style: kH3TitleStyle,
                    ),
                    const SizedBox(height: 10),
                    Flexible(
                      fit: FlexFit.loose,
                      child: SizedBox(
                        height: 200,
                        child: Form(
                          key: formKey,
                          child: Column(
                            children: [
                              Flexible(
                                flex: 1,
                                fit: FlexFit.loose,
                                child:
                                    TextFormFieldUserInformationsConfirmationWidget(
                                  type: FormType.name,
                                  controller: nameController,
                                ),
                              ),
                              Flexible(
                                flex: 1,
                                fit: FlexFit.loose,
                                child:
                                    TextFormFieldUserInformationsConfirmationWidget(
                                  type: FormType.phoneNumber,
                                  controller: phoneNumberController,
                                ),
                              ),
                              Flexible(
                                flex: 1,
                                fit: FlexFit.loose,
                                child:
                                    TextFormFieldUserInformationsConfirmationWidget(
                                  type: FormType.address,
                                  controller: addressController,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(height: 20),
                    ButtonWidget(
                        onPressed: () {
                          print('lol');
                          if (formKey.currentState!.validate()) {
                            print(nameController.text);
                            print(phoneNumberController.text);
                            print(addressController.text);
                          }
                        },
                        text: 'Confirm'),
                  ],
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

It consists of a SingleChildScrollView and inside it there is a Column which holds thre Flexible widgets; the first one is the 'Quantity' title, the second one is the two cards of the medication name and quantity, and the third one is the form.

What I want is to make the form go up when the keyboard gets triggered, but it doesn't want to do that, all it does is to show the keyboard and then close it instanly, and it doesn't give me the time to add text, as soon as the keyboard opens it closes

Mikelenjilo
  • 171
  • 1
  • 12

1 Answers1

1

Put These Two outside of your build method:

final double height = MediaQuery.of(context).size.height;
final GlobalKey<FormState> formKey = GlobalKey<FormState>();

For more information, visit this thread: StackOverflow answer

Ali Punjabi
  • 452
  • 4
  • 19