Goku
Goku

Reputation: 9692

How to create custom stepper in flutter?

I want to create this type of stepper in flutter

enter image description here

till now i have tried this two way

Widget get stepper =>
      Container(
          padding: EdgeInsets.all(15),
          color: Colors.white,
          child: ListView.builder(
              itemCount: stepperLIst.length,
              shrinkWrap: true,
              physics: NeverScrollableScrollPhysics(),
              itemBuilder: (context, position) {
                return IntrinsicHeight(
                  child: Container(
                    margin: const EdgeInsets.only(bottom: 20),
                    child: Row(
                        crossAxisAlignment: CrossAxisAlignment.stretch,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Column(
                            mainAxisSize: MainAxisSize.min,
                            verticalDirection: VerticalDirection.down,
                            children: [
                              Image.asset(stepperLIst[position].iconName),
                              SizedBox(height: 10),
                              CustomPaint(painter: LineDashedPainter(lineColor: Colors.grey))

                            ],
                          ),
                          SizedBox(width: 10),
                          Expanded(
                            child: Column(
                              mainAxisSize: MainAxisSize.min,
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text(
                                  stepperLIst[position].tittle,
                                  style: BaseStyles.textStyle.copyWith(fontFamily: BaseFonts.bold),
                                ),
                                SizedBox(height: 10),
                                Text(
                                  stepperLIst[position].value,
                                  style: BaseStyles.textStyle,
                                )
                              ],
                            ),
                          )
                        ]),
                  ),
                );
              }));

And also using stack

  Widget get stepper2 =>
  Container(
      padding: EdgeInsets.all(15),
      color: Colors.white,
      child: ListView.builder(
          itemCount: stepperLIst.length,
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          itemBuilder: (context, position) {
            return Stack(
              children: <Widget>[
                Positioned(
                  left: 0,
                  top: 0,
                  bottom: 0,
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    verticalDirection: VerticalDirection.down,
                    children: [
                      Image.asset(stepperLIst[position].iconName),
                      SizedBox(height: 10),
                      CustomPaint(painter: LineDashedPainter(lineColor: Colors.grey))

                    ],
                  ), // replace with your image
                ),
                Padding(
                  padding: const EdgeInsets.only(left: 40),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        stepperLIst[position].tittle,
                        style: BaseStyles.textStyle.copyWith(fontFamily: BaseFonts.bold),
                      ),
                      SizedBox(height: 10),
                      Text(
                        stepperLIst[position].value,
                        style: BaseStyles.textStyle,
                      )
                    ],
                  ),
                )
              ],
            );
          }));

Using above code I'm not getting exact output

can anybody help me to create this type of stepper

If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.

Upvotes: 2

Views: 14415

Answers (5)

Texv
Texv

Reputation: 1869

This is a late response but since I found this question unanswered, here is my solution. It is based on Flutter version 3+ but also works on Flutter 2+.

Method 1 - Using Row/Column Widgets

Here I use 2 rows inside a column and repeat them in a listview. The VerticalDivider widget is a straight line but you can use other methods such as CustomPaint or Container to create dotted lines or use libraries such as flutter_dash

Click here to see the practical solution demo on DartPad or reveal here

List<Map<String, dynamic>> userInfoList = [
    {
      'icon': const Icon(Icons.info, color: Colors.orange),
      'title': 'About',
      'content':
          '\$ - American - Restuarant - Western Food\nLocally Resto with the one and only master recipe.\nIn this industry since 1988 - +1182 218 281',
    },
    {
      'icon': const Icon(Icons.web, color: Colors.lightBlueAccent),
      'title': 'Website',
      'content': 'www.moscorestourant.com',
    },
    {
      'icon': const Icon(Icons.location_on, color: Colors.pink),
      'title': 'Location',
      'content': '100 Peachtree Boston 30308',
    },
    {
      'icon': const Icon(Icons.person, color: Colors.greenAccent),
      'title': 'Contact Person',
      'content': 'Jenny F.\[email protected]\n+ 999 999 999',
    },
  ];

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Material(
        child: SingleChildScrollView(
          child: ListView.builder(
            itemCount: userInfoList.length,
            physics: const NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            itemBuilder: (BuildContext content, int index) {
              return Padding(
                padding: const EdgeInsets.only(bottom: 5.0),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Expanded(
                          flex: 1,
                          child: userInfoList[index]['icon'],
                        ),
                        Expanded(
                          flex: 10,
                          child: Text(
                            userInfoList[index]['title'],
                            maxLines: null,
                            style: const TextStyle(
                              color: Colors.black,
                              fontWeight: FontWeight.w700,
                              fontSize: 16.0,
                            ),
                          ),
                        ),
                      ],
                    ),
                    IntrinsicHeight(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Expanded(
                            flex: 1,
                            child: VerticalDivider(
                              color: Colors.black,
                              thickness: 2.0,
                            ),
                          ),
                          Expanded(
                            flex: 10,
                            child: Text(
                              userInfoList[index]['content'],
                              maxLines: null,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              );
            },
          ),
        ),
      ),
    );

Method 2 - Using Stepper Widget

While the design is not exactly like yours, it is still a possible method that has a similar outcome.

  1. I used the stepIconBuilder parameter of the Stepper() widget to customise the icons.
  2. I used the controlsBuilder parameter of the Stepper() widget to customise the 'next' and 'back' buttons to be shrunk.

Click here to see the practical solution demo on DartPad or reveal here

List<Map<String, dynamic>> userInfoList = [
    {
      'icon': const Icon(Icons.info, color: Colors.orange),
      'title': 'About',
      'content':
      '\$ - American - Restuarant - Western Food\nLocally Resto with the one and only master recipe.\nIn this industry since 1988 - +1182 218 281',
    },
    {
      'icon': const Icon(Icons.web, color: Colors.lightBlueAccent),
      'title': 'Website',
      'content': 'www.moscorestourant.com',
    },
    {
      'icon': const Icon(Icons.location_on, color: Colors.pink),
      'title': 'Location',
      'content': '100 Peachtree Boston 30308',
    },
    {
      'icon': const Icon(Icons.person, color: Colors.greenAccent),
      'title': 'Contact Person',
      'content': 'Jenny F.\[email protected]\n+ 999 999 999',
    },
  ];

  @override
  Widget build(BuildContext context) {
    List<Step> stepsList = <Step>[
      Step(
        title: Text(userInfoList[0]['title']),
        subtitle: Text(userInfoList[0]['content']),
        content: Container(),
      ),
      Step(
        title: Text(userInfoList[1]['title']),
        subtitle: Text(userInfoList[1]['content']),
        content: Container(),
      ),
      Step(
        title: Text(userInfoList[2]['title']),
        subtitle: Text(userInfoList[2]['content']),
        content: Container(),
      ),
      Step(
        title: Text(userInfoList[3]['title']),
        subtitle: Text(userInfoList[3]['content']),
        content: Container(),
      ),
    ];

    return SafeArea(
      child: Material(
        child: SingleChildScrollView(
          child: Stepper(
            steps: stepsList,
            connectorColor: MaterialStateProperty.all(
              Colors.black,
            ),
            controlsBuilder: (BuildContext context, _) {
              return const SizedBox.shrink();
            },
            stepIconBuilder: (int step, StepState state) {
              return userInfoList[step]['icon'];
            },
            onStepTapped: (int index) {},
          ),
        ),
      ),
    );

One of the main issue with this method is that the icons/steps have a background color that shares the same parameter (connectorColor) as the vertical lines. This means to remove the Icon background using Colors.transparent you would also lose the vertical lines.

Upvotes: 1

Rajnish Sharma
Rajnish Sharma

Reputation: 36

hope this package helps: another_stepper: ^1.0.4

AnotherStepper( stepperList: stepperData, stepperDirection: Axis.vertical, horizontalStepperHeight: 70, )

Upvotes: 1

rico.wy
rico.wy

Reputation: 1

I have idea ~

Stack(
        children: [
          Container(
            margin: const EdgeInsets.only(left: 24, top:2),
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 0),
            decoration: shown
                ? const BoxDecoration(
                    border: Border(
                        left: BorderSide(
                    width: 2,
                    color: Color(0xFFDDDDDD),
                  )))
                : null,
            child: Padding(
                padding: const EdgeInsets.only(bottom: 20),
                child: Text(txt,
                    style: const TextStyle(
                      color: Color(0xFF1A1A1A),
                      fontWeight: FontWeight.w400,
                      fontSize: 13.0,
                    ))),
          ),
          const SizedBox(
            height: 0,
            width: 50,
            child: Icon(Icons.circle, color: Color(0xFF222222), size: 16),
          ),
        ],
      )

Demo https://img.alicdn.com/imgextra/i3/O1CN01TMfTZI1MFzdk535xL_!!6000000001406-0-tps-377-254.jpg

Upvotes: 0

Sagar R Anghan
Sagar R Anghan

Reputation: 281

I try to come close to your answer. I know it's too late to reply. but I am working on my issue and surfing the internet. I found your question and I get soln for that so, here it is...

import 'package:flutter/material.dart';

class CustomStepper extends StatelessWidget {
  const CustomStepper({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Container(
              margin: const EdgeInsets.only(left: 8, right: 5),
              height: 18,
              width: 18,
              decoration: BoxDecoration(
                  color: Colors.red,
                  shape: BoxShape.circle,
                  border: Border.all(color: Colors.black)),
            ),
            const Text("Title",style: TextStyle(fontWeight: FontWeight.bold)),
          ],
        ),
        Container(
          margin: const EdgeInsets.only(left: 17),
          padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 5),
          decoration: const BoxDecoration(
              border: Border(
                  left: BorderSide(
            color: Colors.red,
          ))),
          child: const Text('SubTitle\nAbc'),
        ),
      ],
    );
  }
}

Result

Upvotes: 1

Alok
Alok

Reputation: 8988

I have some resources to share with you. Just check those out and see if that works out for you. These are:

And if you really want those staggered lines in place of a single vertical lines between the icons in the Stepper, then check out the code of the library and make your own widget like that with some minimal changes.

Upvotes: 0

Related Questions