Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - How to fill remaining space in Stepper controls builder?

In the screenshot, I want to get the next and back buttons to the bottom of the screen.

enter image description here

The stepper has a parameter, controlsBuilder that allows you to build out the layout for the controls. If it's just a simple row, It's placed right underneath the content.

Apparently, the Stepper is a flexible wrapper. I'm not sure what that means. I think it means that the Stepper is considered a flex object because it contains a scrollable area (for the content). Having read the docs, if I'm understanding correctly, it says that I cannot use an Expanded or a Column with a max size in the mainAxis because the stepper is essentially a scrollable area, meaning any RenderBox inside it has unbounded constraints.

So, what are some ways the controls builder can be pushed down to the bottom?

Widget _createEventControlBuilder(BuildContext context, {VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: <Widget>[
      FlatButton(
        onPressed: onStepCancel,
        child: const Text('BACK'),
      ),
      FlatButton(
        onPressed: onStepContinue,
        child: const Text('NEXT'),
      ),
    ]
);
  }

I did try wrapping the above row in a LayoutBuilder as well as another attempt using a SizedBox, setting the height to MediaQuery.of(context).size.height;. It does push it near to the bottom (not quite as much as I like), but the problem is that now there is space beneath controls, causing the screen to scroll down into empty space.

Full code:

    @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
    title: Text("Create an Event"),
  ),
  body: Form(
    key: _eventFormKey,
    child: Stepper(
        type: StepperType.horizontal,
        currentStep: _currentStep,
        controlsBuilder: _createEventControlBuilder,
        onStepContinue: () {
          if (_currentStep + 1 >= MAX_STEPS)
            return;
          setState(() {
            _currentStep += 1;
          });
          },
        onStepCancel: () {
          if (_currentStep + 1 >= MAX_STEPS)
            return;
          setState(() {
            _currentStep -= 1;
          });
        },
        steps: <Step>[
          Step(
            title: Text("Name"),
            isActive: 0 == _currentStep,
            state: _getStepState(0),
            content: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Container(
                  margin: EdgeInsets.only(bottom: 10.0),
                  child: Text(
                    "Give your event a cool name",
                    style: Theme.of(context).textTheme.title,
                  ),
                ),
                TextFormField(
                  maxLines: 1,
                  maxLength: 50,
                  maxLengthEnforced: true,
                  decoration: InputDecoration(
                    hintText: "e.g. Let's eat cheeseburgers!",
                  ),
                  validator: (value) {
                    if (value.trim().isEmpty)
                      return "Event name required.";
                  },
                )
              ],
            )
          ),

          Step(
            title: Text("Type"),
            isActive: 1 == _currentStep,
            state: _getStepState(1),
            content: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Container(
                  margin: EdgeInsets.only(bottom: 10.0),
                  child: Text(
                    "Select an event type",
                    style: Theme.of(context).textTheme.title,
                  ),
                ),
                Container(
                  margin: EdgeInsets.only(bottom: 10.0),
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: DropdownButton<int>(
                            items: _stepTwoDropdownItems,
                            hint: Text("Select event type"),
                            isExpanded: true,
                            value: _eventTypeSelectedIndex,
                            onChanged: (selection) {
                              setState(() {
                                _eventTypeSelectedIndex = selection;
                              });
                            }),
                      )
                    ],
                  )
                )
              ],
            )
          ),
      ]
    ),
  ),
);
}
like image 627
ShrimpCrackers Avatar asked Dec 27 '18 20:12

ShrimpCrackers


People also ask

How do you customize stepper in flutter?

To customize the color, border, etc., wrap a stepper widget inside a Container and specify it's decoration argument.

How do you remove the padding from a stepper flutter?

you can customize the whole stepper widget to delete the padding, follow these steps: create dart file called custom_stepper for example. put the code at the bottom here in this file(note that it's very big code) use the CustomStepper widget not Stepper.

How do you align stepper and text in flutter?

Just set type: StepperType. horizontal .

How do I change the stepper color on my flutter?

Use Your Existing Theme Colors. For some reason, stepper does not inherit your main MaterialApp() 's theme. But you can wrap your Stepper() widget with Theme() and use your primary theme's colors anyways.


1 Answers

I think you can create your own Stepper , or you can try this 'hack' :

Create two variables to store the callbacks:

      VoidCallback _onStepContinue;
      VoidCallback _onStepCancel;

Put your Form inside a Stack :

        Stack(
                children: <Widget>[
                  Form(
                    child: Stepper(

Change your createEventControlBuilder method:

          Widget _createEventControlBuilder(BuildContext context,
              {VoidCallback onStepContinue, VoidCallback onStepCancel}) {
            _onStepContinue = onStepContinue;
            _onStepCancel = onStepCancel;
            return SizedBox.shrink();
          }

Add your custom buttoms :

      Widget _bottomBar() {
        return Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              FlatButton(
                onPressed: () => _onStepCancel(),
                child: const Text('BACK'),
              ),
              FlatButton(
                onPressed: () => _onStepContinue(),
                child: const Text('NEXT'),
              ),
            ]);
      } 

This is how your Stack will looks like :

    Stack(
                children: <Widget>[
                  Form(
                    child: Stepper(
                    ....
                   ), //Form
                    Align(
                    alignment: Alignment.bottomCenter,
                    child: _bottomBar(),
                    )

I know this is a little dirty, but you could try , otherwise I recommend you to create your own Widget.

like image 199
diegoveloper Avatar answered Sep 18 '22 18:09

diegoveloper