'Flutter: How to make a button like this?

I tried to use TextButton.Icon to make the effect as following. But I found that the words can only be at the left or right of the icon. How can I put the words under the icon like this?

enter image description here



Solution 1:[1]

  1. the simplest way to create such things is to use column and row widget properly.
  2. i added a full code with the screenshot check it below [1]: https://i.stack.imgur.com/hRzy9.png
  3. created a reusable widget for icon with button and added it in my main class i.e test class
class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            const SizedBox(height: 10,),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                IconWithTextButton(icon:const Icon(Icons.lock, color: Colors.red,),text: "Lock",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.alarm, color: Colors.amber),text: "Alarm",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.call, color: Colors.green),text: "call",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.wrong_location_sharp, color: Colors.greenAccent),text: "location",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.add, color: Colors.tealAccent),text: "Add",onClicked: (){},),
              ],
            ),
            const SizedBox(height: 20,),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                IconWithTextButton(icon: const Icon(Icons.lock, color: Colors.red,),text: "Lock",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.alarm, color: Colors.amber),text: "Alarm",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.call, color: Colors.green),text: "call",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.wrong_location_sharp, color: Colors.greenAccent),text: "location",onClicked: (){},),
                IconWithTextButton(icon:const Icon(Icons.add, color: Colors.tealAccent),text: "Add",onClicked: (){},),
              ],
            )
          ],
        ),
      ),
    );
  }
}
  1. this is reusable widget with reusable text, reusable onclick and reusable icon
class IconWithTextButton extends StatelessWidget {
  String text;
  Icon icon;
  VoidCallback onClicked;
  IconWithTextButton({Key? key, required this.text, required this.onClicked, required this.icon}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onClicked,
      child: Container(
        child: Column(
          children: [
            icon,
            const SizedBox(height: 10,),
            Text(text),
          ],
        ),
      ),
    );
  }
}


 

Solution 2:[2]

You can use Column Widget and populate its children with Icon and TextField. Then Wrap the whole widget with GestureDetector for on pressed functionality. You can also wrap it with InkWell and Material to get splash effect like in other buttons.

Solution 3:[3]

You need not wrap with column.

TextButton(
        onPressed:(){},
        child: Column(
          children: [
            Icon(Icons.play_arrow,color:Colors.green),
            Text(
              'Hello',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),

Solution 4:[4]

I think GirdView Widget the best way to make button like this-

GridView.count(
    crossAxisCount: 4,
    children:  List<Widget>.generate(16, (index) {
      return  GridTile(
        child:GestureDetector(  
          onTap:(){
            print(index.toString());
          },
      child:    Card(
          color: Colors.blue.shade200,
          child:  Column(
            children:[  Text('tile $index'),
                         Icon(Icons.alarm)
          ])
        )),
     );
    }),
  ),
 

With help of index parameter you can pass function according to button type. If this answer helped you .please upvote the answer . Thanks!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sumed
Solution 2 Divyam Makar
Solution 3 Rohit Chaurasiya
Solution 4 Ashutosh singh