How can I create something similar to a FloatingActionButton
?

- 237,138
- 77
- 654
- 440

- 3,331
- 6
- 19
- 21
26 Answers
RawMaterialButton is better suited I think.
RawMaterialButton(
onPressed: () {},
elevation: 2.0,
fillColor: Colors.white,
child: Icon(
Icons.pause,
size: 35.0,
),
padding: EdgeInsets.all(15.0),
shape: CircleBorder(),
)

- 237,138
- 77
- 654
- 440

- 6,954
- 4
- 24
- 30
-
Although FloatingActionButton is also an option, this is definitely the better approach. – subwaymatch Aug 09 '19 at 21:56
-
20I'm getting a large horizontal padding with this approach, and I can't remove it no matter what I try. Any ideas? – Rod Sep 03 '19 at 12:24
-
8I solved this issue using the constraints property of RawMaterialButton constraints: BoxConstraints(minWidth: 36.0, maxWidth: 36.0, minHeight: 36.0, maxHeight: 36.0 it's probably not the best solution, but it worked. – Mualki Oct 17 '19 at 12:08
-
2to remove padding around button completely also add `materialTapTargetSize: MaterialTapTargetSize.shrinkWrap` – kashlo Apr 22 '20 at 15:34
-
2For me, to remove padding I added: `constraints: BoxConstraints.expand(width: 42, height: 42),` – Leonardo Sep 07 '20 at 15:19
-
3Best approch to me was to combine, `materialTapTargetSize: MaterialTapTargetSize.shrinkWrap`, `padding: EdgeInsets.all(8)` and `constraints: BoxConstraints(minWidth: 0)` – Pedro Romão Feb 06 '21 at 00:16
-
2At the time of this writing, the Flutter documentation lists `RawMaterialButton` as obsolete. Why it's not marked with an `@Deprecated` I don't know - it might be because it's still used internally (by `FloatingActionButton`, for instance). – Elte Hupkes Nov 14 '21 at 13:41
Update (use new ElevatedButton
)
ElevatedButton
(with less customizations)ElevatedButton( onPressed: () {}, child: Icon(Icons.menu, color: Colors.white), style: ElevatedButton.styleFrom( shape: CircleBorder(), padding: EdgeInsets.all(20), backgroundColor: Colors.blue, // <-- Button color foregroundColor: Colors.red, // <-- Splash color ), )
ElevatedButton
(with more customizations)ElevatedButton( onPressed: () {}, child: Icon(Icons.menu), style: ButtonStyle( shape: MaterialStateProperty.all(CircleBorder()), padding: MaterialStateProperty.all(EdgeInsets.all(20)), backgroundColor: MaterialStateProperty.all(Colors.blue), // <-- Button color overlayColor: MaterialStateProperty.resolveWith<Color?>((states) { if (states.contains(MaterialState.pressed)) return Colors.red; // <-- Splash color }), ), )
Using
InkWell
ClipOval( child: Material( color: Colors.blue, // Button color child: InkWell( splashColor: Colors.red, // Splash color onTap: () {}, child: SizedBox(width: 56, height: 56, child: Icon(Icons.menu)), ), ), )
Output (same for the last two):

- 237,138
- 77
- 654
- 440
-
This is the better solution since it involves using the more known ElevatedButton, and make minor customizations, thus gaining all the designed behavior from a Material button – Shahar Hajdu Apr 09 '23 at 15:15
-
You just need to use the shape: CircleBorder()
MaterialButton(
onPressed: () {},
color: Colors.blue,
textColor: Colors.white,
child: Icon(
Icons.camera_alt,
size: 24,
),
padding: EdgeInsets.all(16),
shape: CircleBorder(),
)

- 4,684
- 1
- 18
- 18
You can use InkWell to do that:
A rectangular area of a Material that responds to touch.
Below example demonstrate how to use InkWell
. Notice: you don't need StatefulWidget
to do that. I used it to change the state of the count.
Example:
import 'package:flutter/material.dart';
class SettingPage extends StatefulWidget {
@override
_SettingPageState createState() => new _SettingPageState();
}
class _SettingPageState extends State<SettingPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new InkWell(// this is the one you are looking for..........
onTap: () => setState(() => _count++),
child: new Container(
//width: 50.0,
//height: 50.0,
padding: const EdgeInsets.all(20.0),//I used some padding without fixed width and height
decoration: new BoxDecoration(
shape: BoxShape.circle,// You can use like this way or like the below line
//borderRadius: new BorderRadius.circular(30.0),
color: Colors.green,
),
child: new Text(_count.toString(), style: new TextStyle(color: Colors.white, fontSize: 50.0)),// You can add a Icon instead of text also, like below.
//child: new Icon(Icons.arrow_forward, size: 50.0, color: Colors.black38)),
),//............
),
),
);
}
}
If you want to get benefit of splashColor
, highlightColor
, wrap InkWell
widget using a Material
widget with material type circle. And then remove decoration
in Container
widget.
Outcome:

- 21,001
- 12
- 102
- 104
-
Blassanka, thanks for the information. I ended up using the FloatingActionButton instead. But your solution will come in handy for other scenarios in the future. – Edmand Looi Apr 13 '18 at 16:06
-
2
If you need a background image, you can use CircleAvatar with IconButton. Set the backgroundImage property.
CircleAvatar(
backgroundImage: NetworkImage(userAvatarUrl),
)
Example with button:
CircleAvatar(
backgroundColor: Colors.blue,
radius: 20,
child: IconButton(
padding: EdgeInsets.zero,
icon: Icon(Icons.add),
color: Colors.white,
onPressed: () {},
),
),

- 48,840
- 22
- 240
- 204
You can easily do the following:
FlatButton(
onPressed: () {
},
child: new Icon(
Icons.arrow_forward,
color: Colors.white,
size: 20.0,
),
shape: new CircleBorder(),
color: Colors.black12,
)

- 3,572
- 25
- 36
RaisedButton is depricated, now you can create this by ElevatedButton.
ElevatedButton(
onPressed: () {},
child: Icon(Icons.add, color: Colors.white),
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(20),
primary: Colors.blue,
onPrimary: Colors.black,
),
)

- 5,491
- 3
- 31
- 44
RawMaterialButton(
onPressed: () {},
constraints: BoxConstraints(),
elevation: 2.0,
fillColor: Colors.white,
child: Icon(
Icons.pause,
size: 35.0,
),
padding: EdgeInsets.all(15.0),
shape: CircleBorder(),
)
note down constraints: BoxConstraints()
, it's for not allowing padding in left.
Happy fluttering!!

- 1,310
- 1
- 10
- 26

- 447
- 1
- 7
- 11
There actually is an example how to create a circle IconButton similar to the FloatingActionButton.
Ink(
decoration: const ShapeDecoration(
color: Colors.lightBlue,
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(Icons.home),
onPressed: () {},
),
)
To create a local project with this code sample, run:
flutter create --sample=material.IconButton.2 mysample

- 547
- 1
- 9
- 12
Using ElevatedButton:
ElevatedButton(
onPressed: () {},
child: Icon(
Icons.add,
color: Colors.white,
size: 60.0,
),
style: ElevatedButton.styleFrom(
shape: CircleBorder(), primary: Colors.green),
)

- 142
- 3
- 7
2021
If you need it flat (no elevation) as FlatButton is now deprecated.
TextButton(
onPressed: (){},
child: Icon(Icons.arrow_back),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black26),
shape: MaterialStateProperty.all(const CircleBorder())),
);

- 1,222
- 10
- 10
I created a version with correct clipping, elevation and border. Feel free to customize it.
Material(
elevation: 2.0,
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(50),
color: Colors.white,
child: InkWell(
onTap: () => null,
child: Container(
padding: EdgeInsets.all(9.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: Colors.blue, width: 1.4)),
child: Icon(
Icons.menu,
size: 22,
color: Colors.red,
),
),
),
)),

- 1,053
- 13
- 13
-
1This part was what I was missing -> clipBehavior: Clip.hardEdge I guess with this approach any type of button can be created, for example a FAB with onLongPressed. Good job. – Ashkan Sarlak May 04 '22 at 00:59
This code will help you to add button without any unwanted padding,
RawMaterialButton(
elevation: 0.0,
child: Icon(Icons.add),
onPressed: (){},
constraints: BoxConstraints.tightFor(
width: 56.0,
height: 56.0,
),
shape: CircleBorder(),
fillColor: Color(0xFF4C4F5E),
),

- 165
- 1
- 12
I used this one because I like the customisation of the border-radius and size.
Material( // pause button (round)
borderRadius: BorderRadius.circular(50), // change radius size
color: Colors.blue, //button colour
child: InkWell(
splashColor: Colors.blue[900], // inkwell onPress colour
child: SizedBox(
width: 35,height: 35, //customisable size of 'button'
child: Icon(Icons.pause,color: Colors.white,size: 16,),
),
onTap: () {}, // or use onPressed: () {}
),
),
Material( // eye button (customised radius)
borderRadius: BorderRadius.only(
topRight: Radius.circular(10.0),
bottomLeft: Radius.circular(50.0),),
color: Colors.blue,
child: InkWell(
splashColor: Colors.blue[900], // inkwell onPress colour
child: SizedBox(
width: 40, height: 40, //customisable size of 'button'
child: Icon(Icons.remove_red_eye,color: Colors.white,size: 16,),),
onTap: () {}, // or use onPressed: () {}
),
),

- 101
- 1
- 7
There are many ways to create the circle icon button in Flutter. Each of the examples below will use a different method.
- Using ElevatedButton + Icon (recommended)
- Using MaterialButton
- ClipOval + Material + InkWell + Padding + Icon
- IconButton + CircleAvatar
- Ink + IconButton
Using ElevatedButton + Icon
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(30)
),
child: const Icon(
Icons.add,
size: 50,
),
onPressed: () {},
),
Using MaterialButton
MaterialButton(
shape: const CircleBorder(),
color: Colors.red,
padding: const EdgeInsets.all(20),
onPressed: () {},
child: const Icon(
Icons.star,
size: 50,
color: Colors.yellow,
),
)
ClipOval + Material + InkWell + Padding + Icon
ClipOval(
child: Material(
color: Colors.blue,
child: InkWell(
onTap: () {},
child: const Padding(
padding: EdgeInsets.all(20),
child: Icon(
Icons.plus_one,
size: 50,
color: Colors.white,
),
),
),
),
)
IconButton + CircleAvatar
CircleAvatar(
radius: 50,
backgroundColor: Colors.amber,
child: IconButton(
color: Colors.black,
padding: const EdgeInsets.all(20),
iconSize: 50,
icon: const Icon(Icons.shop),
onPressed: () {
// do something
}),
),
Ink + IconButton
Ink(
decoration:
const ShapeDecoration(
shape: CircleBorder(),
color: Colors.purple
),
child: IconButton(
icon: const Icon(Icons.arrow_back),
iconSize: 30,
color: Colors.white,
onPressed: () {},
),
)

- 276
- 2
- 5
My contribution:
import 'package:flutter/material.dart';
///
/// Create a circle button with an icon.
///
/// The [icon] argument must not be null.
///
class CircleButton extends StatelessWidget {
const CircleButton({
Key key,
@required this.icon,
this.padding = const EdgeInsets.all(8.0),
this.color,
this.onPressed,
this.splashColor,
}) : assert(icon != null),
super(key: key);
/// The [Icon] contained ny the circle button.
final Icon icon;
/// Empty space to inscribe inside the circle button. The [icon] is
/// placed inside this padding.
final EdgeInsetsGeometry padding;
/// The color to fill in the background of the circle button.
///
/// The [color] is drawn under the [icon].
final Color color;
/// The callback that is called when the button is tapped or otherwise activated.
///
/// If this callback is null, then the button will be disabled.
final void Function() onPressed;
/// The splash color of the button's [InkWell].
///
/// The ink splash indicates that the button has been touched. It
/// appears on top of the button's child and spreads in an expanding
/// circle beginning where the touch occurred.
///
/// The default splash color is the current theme's splash color,
/// [ThemeData.splashColor].
final Color splashColor;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return ClipOval(
child: Material(
type: MaterialType.button,
color: color ?? theme.buttonColor,
child: InkWell(
splashColor: splashColor ?? theme.splashColor,
child: Padding(
padding: padding,
child: icon,
),
onTap: onPressed,
),
),
);
}
}

- 31
- 1
Not Material solution:
final double floatingButtonSize = 60;
final IconData floatingButtonIcon;
TouchableOpacity(
onTap: () {
/// Do something...
},
activeOpacity: 0.7,
child: Container(
height: floatingButtonSize,
width: floatingButtonSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(floatingButtonSize / 2),
color: Theme.of(context).primaryColor,
boxShadow: [
BoxShadow(
blurRadius: 25,
color: Colors.black.withOpacity(0.2),
offset: Offset(0, 10),
)
],
),
child: Icon(
floatingButtonIcon ?? Icons.add,
color: Colors.white,
),
),
)
You can use GestureDetector instead of TouchableOpacity library.

- 1,425
- 17
- 15
You can also use a RaisedButton with an image inside (for example for social login) like this (sizedbox with fittebox is needed to contraint the image on the specified size):
FittedBox(
fit: BoxFit.scaleDown,
child: SizedBox(
height: 60,
width: 60,
child: RaisedButton(
child: Image.asset(
'assets/images/google_logo.png'),
shape: StadiumBorder(),
color: Colors.white,
onPressed: () {},
),
),
),

- 587
- 1
- 4
- 19
ClipOval(
child: MaterialButton(
color: Colors.purple,
padding: EdgeInsets.all(25.0),
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0)),
child: Text(
'1',
style: TextStyle(fontSize: 30.0),
),
),
),

- 791
- 1
- 9
- 27

- 11
- 1
Below code will create a Circle of radius 25 and will have white color add icon in it. and If user also want to have click method that can be simply achieved by wrapping a Container widget into GestureDetector() or InkWell().
Container(
height: 50,
width: 50,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(50 / 2),
),
child: Center(
child: Icon(
Icons.add,
color: Colors.white,
),
),
),

- 758
- 1
- 9
- 22
Just use the circle shape
MaterialButton(
onPressed: () {
print("Circle button pressed");
},
color: Colors.blue,
textColor: Colors.white,
child: Icon(
Icons.favorite,
size: 20,
),
padding: EdgeInsets.all(16),
//use this class Circleborder() for circle shape.
shape: const CircleBorder(),
)

- 3,331
- 1
- 12
- 20

- 672
- 8
- 29
Material 3 / Flutter 3.7.0-
Here is a CircleIconButton
widget supporting standard, filled, filled tonal and outlined types from Material 3, as described in https://m3.material.io/components/icon-buttons/overview. The widget supports also toggle feature and enabled/disabled states.
import 'package:flutter/material.dart';
enum CircleIconButtonStyle {
standard,
filled,
filledTonal,
outlined,
}
class CircleIconButton extends StatelessWidget {
const CircleIconButton({
super.key,
required this.icon,
this.circleIconButtonStyle = CircleIconButtonStyle.filled,
required this.onPressed,
this.isSelected,
this.selectedIcon,
});
final IconData icon;
final CircleIconButtonStyle circleIconButtonStyle;
final VoidCallback? onPressed;
/// For toggle buttons
final bool? isSelected;
final Widget? selectedIcon;
@override
Widget build(BuildContext context) {
final ColorScheme colors = Theme.of(context).colorScheme;
return IconButton(
onPressed: onPressed,
icon: Icon(icon),
isSelected: isSelected,
selectedIcon: selectedIcon,
style: _CircleIconButtonStyleProvider.getStyle(
circleIconButtonStyle: circleIconButtonStyle,
isEnabled: onPressed != null,
isSelected: isSelected == true,
colors: colors),
);
}
}
// adapted from samples at https://api.flutter.dev/flutter/material/IconButton-class.html
class _CircleIconButtonStyleProvider {
static ButtonStyle? getStyle({
required CircleIconButtonStyle circleIconButtonStyle,
required bool isEnabled,
required bool isSelected,
required ColorScheme colors,
}) {
switch (circleIconButtonStyle) {
case CircleIconButtonStyle.standard:
return null;
case CircleIconButtonStyle.filled:
return isEnabled
? _enabledFilledButtonStyle(isSelected, colors)
: _disabledFilledButtonStyle(isSelected, colors);
case CircleIconButtonStyle.filledTonal:
return isEnabled
? _enabledFilledTonalButtonStyle(isSelected, colors)
: _disabledFilledTonalButtonStyle(isSelected, colors);
case CircleIconButtonStyle.outlined:
return isEnabled
? _enabledOutlinedButtonStyle(isSelected, colors)
: _disabledOutlinedButtonStyle(isSelected, colors);
}
}
static ButtonStyle _enabledFilledButtonStyle(
bool selected,
ColorScheme colors,
) {
return IconButton.styleFrom(
foregroundColor: selected ? colors.onPrimary : colors.primary,
backgroundColor: selected ? colors.primary : colors.surfaceVariant,
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: selected
? colors.onPrimary.withOpacity(0.08)
: colors.primary.withOpacity(0.08),
focusColor: selected
? colors.onPrimary.withOpacity(0.12)
: colors.primary.withOpacity(0.12),
highlightColor: selected
? colors.onPrimary.withOpacity(0.12)
: colors.primary.withOpacity(0.12),
);
}
static ButtonStyle _disabledFilledButtonStyle(
bool selected,
ColorScheme colors,
) {
return IconButton.styleFrom(
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
);
}
static ButtonStyle _enabledFilledTonalButtonStyle(
bool selected,
ColorScheme colors,
) {
return IconButton.styleFrom(
foregroundColor:
selected ? colors.onSecondaryContainer : colors.onSurfaceVariant,
backgroundColor:
selected ? colors.secondaryContainer : colors.surfaceVariant,
hoverColor: selected
? colors.onSecondaryContainer.withOpacity(0.08)
: colors.onSurfaceVariant.withOpacity(0.08),
focusColor: selected
? colors.onSecondaryContainer.withOpacity(0.12)
: colors.onSurfaceVariant.withOpacity(0.12),
highlightColor: selected
? colors.onSecondaryContainer.withOpacity(0.12)
: colors.onSurfaceVariant.withOpacity(0.12),
);
}
static ButtonStyle _disabledFilledTonalButtonStyle(
bool selected,
ColorScheme colors,
) {
return IconButton.styleFrom(
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
);
}
static ButtonStyle _enabledOutlinedButtonStyle(
bool selected,
ColorScheme colors,
) {
return IconButton.styleFrom(
backgroundColor: selected ? colors.inverseSurface : null,
hoverColor: selected
? colors.onInverseSurface.withOpacity(0.08)
: colors.onSurfaceVariant.withOpacity(0.08),
focusColor: selected
? colors.onInverseSurface.withOpacity(0.12)
: colors.onSurfaceVariant.withOpacity(0.12),
highlightColor: selected
? colors.onInverseSurface.withOpacity(0.12)
: colors.onSurface.withOpacity(0.12),
side: BorderSide(color: colors.outline),
).copyWith(
foregroundColor:
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return colors.onInverseSurface;
}
if (states.contains(MaterialState.pressed)) {
return colors.onSurface;
}
return null;
}),
);
}
static ButtonStyle _disabledOutlinedButtonStyle(
bool selected,
ColorScheme colors,
) {
return IconButton.styleFrom(
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor:
selected ? colors.onSurface.withOpacity(0.12) : null,
side:
selected ? null : BorderSide(color: colors.outline.withOpacity(0.12)),
);
}
}
Flutter has an IconBox
which can be used to place a circle around an Icon
. For a GestureTapCallback
to be added, The IconBox
has an onTap
.
IconBox(
onTap: () => Navigator.pop(context),
bgColor: AppColor.translucent,
child: Icon(Icons.arrow_back_ios_new_rounded),
)
Or optionally use an IconButton
.
IconButton(
onPressed: () => Navigator.pop(context),
icon: const IconBox(bgColor: AppColor.translucent,
child: Icon(Icons.arrow_back_ios_new_rounded),
),
),

- 71
- 6
Try out this Card
Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0), // half of height and width of Image
),
child: Image.asset(
"assets/images/home.png",
width: 50,
height: 50,
),
)

- 19,824
- 17
- 99
- 186

- 757
- 1
- 6
- 18
Card(
elevation: 4.0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(150),
),
child: InkWell(
onTap: (){},
child: Container(
width: 40,
height: 40,
padding: const EdgeInsets.all(3.0),
decoration: const BoxDecoration(
shape: BoxShape.circle, color: backGroundColor),
child: Image.asset(imageUrl)),
)),

- 344
- 4
- 9
Container(
width: 70.w,
height: 70.h,
alignment: AlignmentDirectional.topCenter,
child: MaterialButton(
onPressed: () {},
color: Color(0xff022C43),
textColor: Colors.white,
child: Icon(
Icons.arrow_forward,
size: 24,
),
padding: EdgeInsets.all(16),
shape: CircleBorder(),
)
)

- 1,057
- 1
- 11
- 27

- 41
- 1
-
As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 10 '22 at 02:03
-
please remove .h and .w , this is for used third-party package . please edit your answer . – Esmaeil Ahmadipour May 11 '22 at 11:12