InkWell not showing ripple effect - flutter

Tapping the container triggers the onTap() handler but does not show any ink splash effect.
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new InkWell(
onTap: (){print("tapped");},
child: new Container(
width: 100.0,
height: 100.0,
color: Colors.orange,
),
),
),
);
}
}
I tried putting the InkWell inside the Container as well but in vain.

I think adding color to the container is covering over the ink effect
https://api.flutter.dev/flutter/material/InkWell/InkWell.html
This code seems to work
body: new Center(
child: new Container(
child: new Material(
child: new InkWell(
onTap: (){print("tapped");},
child: new Container(
width: 100.0,
height: 100.0,
),
),
color: Colors.transparent,
),
color: Colors.orange,
),
),
just click the middle square.
Edit: I found the bug report. https://github.com/flutter/flutter/issues/3782
This is actually as expected, though we should update the docs to make it clearer.
What's going on is that the Material spec says that the splashes are actually ink on the Material. So when we splash, what we do is we literally have the Material widget do the splash. If you have something on top of the Material, we splash under it, and you can't see it.
I have wanted to add a "MaterialImage" widget that conceptually prints its image into the Material as well so that then the splashes would be over the image. We could have a MaterialDecoration which does something similar for a Decoration. Or we could have Material itself take a decoration. Right now it takes a color, but we could extend that to taking a whole decoration. It's not clear whether it's really material-spec-compatible to have a material with a gradient, though, so I'm not sure whether we should do that.
In the short run, if you just need a workaround, you can put a Material on top of the container, with the material set to use the "transparency" type, and then put the ink well inside that.
--hixie
Update: Hixie merged a new Ink solution last year. The Ink provides a convenient way to splash over images.
testWidgets('Does the Ink widget render anything', (WidgetTester tester) async {
await tester.pumpWidget(
new Material(
child: new Center(
child: new Ink(
color: Colors.blue,
width: 200.0,
height: 200.0,
child: new InkWell(
splashColor: Colors.green,
onTap: () { },
),
),
),
),
);
Material(
color: Colors.grey[800],
child: Center(
child: Ink.image(
image: AssetImage('cat.jpeg'),
fit: BoxFit.cover,
width: 300.0,
height: 200.0,
child: InkWell(
onTap: () { /* ... */ },
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text('KITTEN', style: TextStyle(fontWeight: FontWeight.w900, color: Colors.white)),
),
)
),
),
),
)
Please Note: I did not test the new Ink Widget. I coped the code from ink_paint_test.dart and the Ink class docs
https://github.com/Hixie/flutter/blob/1f6531984984f52328e66c0cd500a8d517964564/packages/flutter/test/material/ink_paint_test.dart
https://github.com/flutter/flutter/pull/13900
https://api.flutter.dev/flutter/material/Ink-class.html

Screenshot:
Use Ink widget wrapped in an InkWell.
InkWell(
onTap: () {}, // Handle your onTap
child: Ink(
width: 200,
height: 200,
color: Colors.blue,
),
)

The InkWell widget must have a Material widget as an ancestor otherwise it can't show effects. E.g.:
Material(
child : InkWell(
child : .....
you have to add onTap method to see the actual effects as like
Buttons {RaisedButton,FlatButton etc}.
e.g -> Material(
child : InkWell(
onTap : (){}
child : .....
Let's come to the main points see some examples below and try to understand
the actual concepts of InkWell.
In Below example Material is parent of InkWell with onTap but it still not working. Please try to understand the concept of it. You should provide some margin to container or other widget to show the effects. Actually below code working fine but we can't see because we did not provide any margin or align so it has no space to show the effects.
Widget build(BuildContext context) {
return Center(
child: Material(
child: new InkWell(
onTap: () {
print("tapped");
},
child: new Container(
width: 100.0,
height: 100.0,
color: Colors.orange,
),
),
),
);
}
Below example show InkWell effects only to upwards because we provide space {margin}.
Widget build(BuildContext context) {
return Center(
child: Material(
child: new InkWell(
onTap: () {
print("tapped");
},
child: new Container(
margin: EdgeInsets.only(top: 100.0),
width: 100.0,
height: 100.0,
color: Colors.orange,
),
),
),
);
}
Below exp. show the effects in all the page because center create margin from all the side. Centre align it's child widget from top, left, right and bottom.
Widget build(BuildContext context) {
return Center(
child: Material(
child: new InkWell(
onTap: () {
print("tapped");
},
child: Center(
child: new Container(
width: 100.0,
height: 100.0,
color: Colors.orange,
),
),
),
),
);
}

InkWell() will never show the ripple effect until you add the
onTap : () {}
or any of the callbacks like onDoubleTap, onLongPress etc.
parameter inside the InkWell as it starts listening to your taps only when you specify this parameter.

I have found this solution for me. I think it can help you:
Material(
color: Theme.of(context).primaryColor,
child: InkWell(
splashColor: Theme.of(context).primaryColorLight,
child: Container(
height: 100,
),
onTap: () {},
),
)
Color is given to Material widget. It is the default color of your widget.
You can adjust color of ripple effect using splashColor property of Inkwell.

A better way is to use the Ink widget instead of any other widget.
Instead of defining color inside container you can define it in Ink widget itself.
Below code will work.
Ink(
color: Colors.orange,
child: InkWell(
child: Container(
width: 100,
height: 100,
),
onTap: () {},
),
)
Do not forget to add a onTap: () {} in the InkWell else it will
not show the ripple effect too.

If you want a Ripple Effect on any widget just:
1- Wrap widget with Material and Inkwell.
2- set color to widget from Material.
3- Never set color to the widget you want it to ripple.
Material (
color: const Color(0xcffFF8906),
child: InkWell(
ontap:() { },
child: Container(
color: Colors.transparent,
height: 80,
width: 80,
)

Quick solution in easy words:
This solution works in any place of the widget tree.
Just add additional Material before InkWell, like so:
return Container(
.......code.......
),
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {},
child: Container(
.......code.......
),
),
),
);
Reference:
https://api.flutter.dev/flutter/material/InkWell-class.html
Section called "The ink splashes aren't visible!"

Wrap the InkWell with Material and use there the color that you need:
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: Material(
color: Colors.orange,
child: new InkWell(
onTap: (){ print("tapped"); },
child: new Container(
width: 100.0,
height: 100.0,
),
),
),
),
);
}
}

This is the best way I found and use it always. You can try it.
Wrap your Widget with InkWell
Wrap InkWell with Material
Set the opacity 0% anyhow. e.g.: color: Colors.white.withOpacity(0.0),
Material(
color: Colors.white.withOpacity(0.0),
child: InkWell(
child: Container(width: 100, height: 100),
onTap: (){print("Wow! Ripple");},
),
)

This is working for me:
Material(
color: Colors.white.withOpacity(0.0),
child: InkWell(
splashColor: Colors.orange,
child: Text('Hello'), // actually here it's a Container wrapping an image
onTap: () {
print('Click');
},
));
After trying many answers here, it was a combination of:
Setting splashColor
Wrapping InkWell in Material(color: Colors.white.withOpacity(0.0), ..)
Thanks to the answers here that make those 2 points

child: Material(
color: Colors.transparent
child: InkWell(
onTap: (){ print("this Ripple!";},
splashColor: Colors.greenAccent,
child: Container(
height:100.0,
color: Colors.white,
),
),
),
Add Material before InkWell and set color to Colors.transparent.

I ran into this same problem trying to create an alternating color of InkWell's in a ListView. In that particular case, there's a simple solution: wrap the alternates in a Container that uses a mostly transparent tint/brightness change -- the InkWell touch animation will still be visible beneath it. No Material needed. Note there are other issues when trying to work around this with a Materal -- e.g., it will override a DefaultTextStyle you're using with the default (it installs an AnimatedDefaultTextStyle) which is a huge pain.

After you added onTap:(){} listener, ripple effect should work fine. It doesn't work if you use BoxShadow() with in the InkWell() widget.

I was able to make my situation work by using a Stack.
Stack(
children: [
MyCustomWidget(), // <--- Put this on bottom
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {},
child: Ink(
width: 100,
height: 100,
),
),
),
],
),
The reason that the other answers on this page weren't working for me is that my custom widget hid the ink effect and I didn't have a plain image (so I couldn't use Ink.image).
Edit:
You still may be able to use Ink.image if you convert the image to the right format.

now using MaterialButton, in newer version flutter
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: MaterialButton(
child: Text(
labelText,
style: TextStyle(fontSize: 22),
),
onPressed: () {},
color: backgroundColor,
height: 45,
minWidth: double.infinity,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(16),
),
),
),
);
}

For handling ripple effect you should use the below rules:
onTap shouldn't be null (or empty).
InkWell must be inside any of the Material Widgets

Single Line:
Use splashColor widget in an InkWell.
InkWell(
onTap: () {}, // Handle your onTap
splashColor: Colors.grey,
child: Container(
width: 200,
height: 200,
),
)

You might have set the properties in theme or parent of the material
ThemeData(
...
splashFactory: NoSplash.splashFactory,
...
)
if you don't want splash effect for specific use it explicitly
InkWell(
splashFactory: NoSplash.splashFactory,
...
child: Row(
...
)
);

Make sure you have not added the below properties in the material theme:
(In my case this was the issue)
splashColor: Colors.transparent
splashFactory: NoSplash.splashFactory
eg:-
MaterialApp(
home:......,
theme: ThemeData(
splashFactory: NoSplash.splashFactory, // Remove this
splashColor: AppColors.transparent, // Remove this OR Change the color
......
),
)

Create a widget that supports tap.
Wrap it in an InkWell widget to manage tap callbacks and ripple
animations.
that's point 2 mentioned in documentation
example:
InkWell(
child: TextButton(
onPressed: () {},
child: Text('Tapped'),
),
),
),

I was hit by a similar problem adding an Inkwell to an existing complex Widget with a Container wrapping a BoxDecoration with a color. By adding the Material and Inkwell in the way suggested the Inkwell was still obscured by the BoxDecoration so I just made the BoxDecoration's color slightly opaque which allowed the Inkwell to be seen

The solution to circular widgets, do like below:
Material(
color: Colors.transparent,
child: Container(
alignment: Alignment.center,
height: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
enableFeedback: true,
iconSize: 40,
icon: Icon(
Icons.skip_previous,
color: Colors.white,
size: 40,
),
onPressed: () {}),
IconButton(
iconSize: 100,
enableFeedback: true,
splashColor: Colors.grey,
icon: Icon(Icons.play_circle_filled, color: Colors.white, size: 100),
padding: EdgeInsets.all(0),
onPressed: () {},
),
IconButton(
enableFeedback: true,
iconSize: 40,
icon: Icon(
Icons.skip_next,
color: Colors.white,
size: 40,
),
onPressed: () {}),
],
),
),
)

For me it was another problem. InkWell was not showing ripple effect when i had onTap function as parameter of my widget defined as below.
Function(Result) onTapItem;
...
onTap: onTapItem(result),
I don't know what's the difference, but next code is working well.
onTap: (){ onTapItem(result); },

Adding transparent color to Material worked in my case:
child: new Material(
color: Colors.transparent
child: new InkWell(
onTap: (){},
child: new Container(
width: 100.0,
height: 100.0,
color: Colors.amber,
),
),
),

Instead of providing the color for the Container widget, provide color for the Material widget.
Material(
color: Colors.orange,
child: InkWell(
onTap: () {
print("tapped");
},
child: Container(
width: 100.0,
height: 100.0,
),
),
)

Related

How to disable tap on the inner child of the InkWell?

I have this widget
InkWell(
onTap: (){
// clicks overAll
},
child: Column(
children: [
Text('Sample one'),
SizedBox(),
Text('Sample two'),
AnotherWidget(),
AnotherWidget2(),// want to disable click only this widget
],
),
);
I want to disable the click only to the AnotherWidget2() widget. but Inkwell not allowing that even If I use IgnorePointer on the AnotherWidget2()
I know that I can put InkWell individually on every widget except AnotherWidget2(). But Is there any way to acheive without putting InkWell on individual widgets?
Try below code hope its help to you. Wrap your AnotherWidget2() with InkWell() and set onTap()=>null
InkWell(
onTap: () {
// clicks overAll
print('clicks overAll');
},
child: Column(
children: [
Text('Sample one'),
SizedBox(),
Text('Sample two'),
Container(
height: 100,
width: 200,
margin: EdgeInsets.all(10),
color: Colors.red,
),
InkWell(
onTap: ()=> null,
child: Container(
height: 100,
width: 200,
margin: EdgeInsets.all(10),
color: Colors.blue,
),
),
],
),
),

How to add ripples effect while using circleavatar in flutter

CircleAvatar(
backgroundColor: Colors.blue,
radius: 25,
child: Icon(Icons.add_call),
),
How to add ripples of different color inside circleavatar
You can use InkWell in this case, and import 'dart:math'; use get Random.
late Color _rippleColor = getRandomColor();
Color getRandomColor() =>
Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: InkWell(
radius: 25,
splashColor: _rippleColor,
customBorder: const CircleBorder(),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.add_call,
),
),
onTap: () {
setState(() {
_rippleColor = getRandomColor();
});
},
),
));
}
Use Ink and InkWell with Material on top of it and set Material shape with CircleBorder()
Material(
elevation: 4.0,
shape: CircleBorder(),
clipBehavior: Clip.antiAlias,
color: Colors.transparent,
child: Ink.image(
image: AssetImage('assets/profile_default.jpg'),
fit: BoxFit.cover,
width: 120.0,
height: 120.0,
child: InkWell(
onTap: () {},
),
),
)
you can change splash color in InkWell property
source: https://medium.com/#RayLiVerified/create-a-rounded-image-icon-with-ripple-effect-in-flutter-eb0f4a720b90

Ripple effect not working with when wrapping a Card in InkWell

After doing a bit of research, I tried to wrap ListTiles with InkWell to get the onTap ripple effect, but it doesn't seem to work. This is what I have:
return AnimationLimiter(
child: Scrollbar(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.myItems.length,
itemBuilder: (context, index) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Material(
/// child: Ink( also tried with Ink and no Ink and no Material just InkWell but no ripple
child: InkWell(
onTap: () => widget.nav(widget.myItems[index]),
splashColor: Colors.red,
child: Card(
child: _itemTile(index),
),
),
),
),
),
),
),
),
);
The ListTile:
return ListTile(
dense: true,
trailing: Icon(Icons.keyboard_arrow_right),
leading: category,
title: Text(
item.title,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
);
I managed to get the ripple effect working by doing onTap: () => {} to the InkWell. But after adding the GestureDetector, the Ripple is gone again.
child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () {},
splashColor: Colors.red,
child: GestureDetector(
onTap: () => widget.nav(widget.myItems[index]),
child: _itemTile(index),
),
),
I even tried this, ripple works, but it the widget.nav function doesn't get called:
Stack(
children: [
Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin:
EdgeInsets.only(bottom: 5.0, left: 2.0, right: 2.0),
child: GestureDetector(
onTap: () {
widget.nav(widget.myItems[index]);
},
child: _itemTile(index),
),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => {},
),
),
)
],
),
Edit* Adding the nav function:
_navToItem(item) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Item(
items: _activityItems.length > 0 ? _activityItems : _items,
showAd: false,
user: userStream,
item: item,
favorites: _favorites,
),
),
);
}
ListTile has a ripple effect by default, so you shouldn't need to add an inkwell. If there isn't a ripple, one of the children is probably causing some issues. Try removing some and see if that helps.
Example
You're correct in using the Stack.
It's necessary due to the way the widget tree is rendered from bottom up, layering each widget on top of each other (which blocks the visual effect of splash if there are children below it.)
The GestureDetector you have in your Stack example won't ever get the tap gesture, cause InkWell below it is taking the event.
Something like this work for you? (Move your widget.nav call to the InkWell onTap:.)
Stack(
children: [
Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin:
EdgeInsets.only(bottom: 5.0, left: 2.0, right: 2.0),
// GESTUREDETECTOR Removed ****************
child: Text('itemTile goes here'),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => print('InkWell tapped! Put widget.nav here!'),
),
),
)
],
)
Please try to understand the concept of it. You should provide some margin to the widget to show the effects. You didn't provide any margin or align so it has no space to show the effects.
Below exp. show the effects in all the page because center creates margin from all the side. The Centre aligns its child widget from the top, left, right and bottom.
Widget build(BuildContext context) {
return Center(
child: Material(
child: new InkWell(
onTap: () {
print("tap");
},
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.red,
),
),
),
),
);
}
In your case:
return AnimationLimiter(
child: Scrollbar(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.myItems.length,
itemBuilder: (context, index) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Material(
/// child: Ink( also tried with Ink and no Ink and no Material just InkWell but no ripple
child: InkWell(
onTap: () => widget.nav(widget.myItems[index]),
splashColor: Colors.red,
child: Center(
child: Card(
child: _itemTile(index),
),
),
),
),
),
),
),
),
),
);
For ListTile case try passing custom ripple color. May be your background and your ripple effect color is same.
There is no need to wrap ListTile with InkWell because it already does it under the hood. We could do this with a Material widget to preserve the ripple effect and to act like a Card widget:
Material(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
elevation: 1,
child: ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
leading: Text('Hello World'),
onTap: () => print('Pressed ListTile'),
),
),
Output:
Please change your code
Card(child: InkWell(child: ListTile(), onTab: () {},),),
First of all Card widget, its child Inkwell and then ListTile.

Raw material button not responding to clicks flutter

Where am I supposed to place the material as the parent of the Raw material button so that it can respond to clicks and show splash color.
The widget tree looks like below.
Widget build(BuildContext context) {
return new Container(
child: new Center(
child: new Stack(
alignment: Alignment.center,
children: <Widget>[
new Container(
child: new Padding(
padding: const EdgeInsets.all(5.0),
child: new Container(
child: new AudioComponent(
updateMe: [WatchableAudioProperties.audioPlayerState],
playerBuilder: (BuildContext context, AudioPlayer
player,
Widget child) {
IconData icon = Icons.play_arrow;
return new RawMaterialButton(
shape: new CircleBorder(),
fillColor: Colors.white,
splashColor: lightAccentColor,
highlightColor: lightAccentColor.withOpacity(0.5),
elevation: 10.0,
highlightElevation: 5.0,
onPressed: (){},
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Icon(
icon,
color: accentColor,
size: 50.0,
),
),
);
},
),
),
),
),
new Container(
height: 151.0,
width: 151.0,
child: waves,
),
],
),
),
);
}
If I add another container onto the stack and put a similar RawMaterial button, it responds as required even without adding a material widget anywhere. What I don't understand why the RawButton in the first container in the stack is not working
How do you expect to have your RawMaterialButton react when you have the following code in it's definition?
onPressed: (){},

How to set the width and height of a button in Flutter?

I have seen that I can't set the width of a ElevatedButton in Flutter. If I have well understood, I should put the ElevatedButton into a SizedBox. I will then be able to set the width or height of the box. Is it correct? Is there another way to do it?
This is a bit tedious to create a SizedBox around every buttons so I'm wondering why they have chosen to do it this way. I'm pretty sure that they have a good reason to do so but I don't see it.
The scaffolding is pretty difficult to read and to build for a beginner.
new SizedBox(
width: 200.0,
height: 100.0,
child: ElevatedButton(
child: Text('Blabla blablablablablablabla bla bla bla'),
onPressed: _onButtonPressed,
),
),
As said in documentation here
Raised buttons have a minimum size of 88.0 by 36.0 which can be
overidden with ButtonTheme.
You can do it like that
ButtonTheme(
minWidth: 200.0,
height: 100.0,
child: RaisedButton(
onPressed: () {},
child: Text("test"),
),
);
match_parent (Full width):
SizedBox(
width: double.infinity, // <-- match_parent
height: double.infinity, // <-- match-parent
child: ElevatedButton(...)
)
or
SizedBox.expand(
child: ElevatedButton(...)
)
Specific width:
SizedBox(
width: 100, // <-- Your width
height: 50, // <-- Your height
child: ElevatedButton(...)
)
With Flutter 2.0 RaisedButton is deprecated and replaced by ElevatedButton.
With that in mind, much more cleaner approach to give custom size to ElevatedButton is minimumSize property of ElevatedButton widget.
Output
Full Code
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green,
onPrimary: Colors.white,
shadowColor: Colors.greenAccent,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0)),
minimumSize: Size(100, 40), //////// HERE
),
onPressed: () {},
child: Text('Hey bro'),
)
Note: Also keep in mind that same approach can be used in new widgets like TextButton and OutlinedButton using TextButton.styleFrom(minimumSize: Size(100, 40)) and OutlinedButton.styleFrom(minimumSize: Size(100, 40)) respectively.
That's because flutter is not about size. It's about constraints.
Usually we have 2 use cases :
The child of a widget defines a constraint. The parent size itself is based on that information. ex: Padding, which takes the child constraint and increases it.
The parent enforce a constraint to its child. ex: SizedBox, but also Column in strech mode, ...
RaisedButton is the first case. Which means it's the button which defines its own height/width. And, according to material rules, the raised button size is fixed.
You don't want that behavior, therefore you can use a widget of the second type to override the button constraints.
Anyway, if you need this a lot, consider either creating a new widget which does the job for you. Or use MaterialButton, which possesses a height property.
I would recommend using a MaterialButton, than you can do it like this:
MaterialButton(
height: 40.0,
minWidth: 70.0,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
child: new Text("push"),
onPressed: () => {},
splashColor: Colors.redAccent,
)
You need to use an Expanded Widget. But, if your button is on a column, the Expanded Widget fills the rest of the column. So, you need to enclose the Expanded Widget within a row.
Row(children: <Widget>[
Expanded(
flex: 1,
child: RaisedButton(
child: Text("Your Text"),
onPressed: _submitForm,
),
),),])
The new buttons TextButton, ElevatedButton, OutlinedButton etc. are to be changed in a different way.
One method I found is from this article: you need to "tighten" a constrained box around the button.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Kindacode.com'),
),
body: Center(
child: ConstrainedBox(
constraints: BoxConstraints.tightFor(width: 300, height: 200),
child: ElevatedButton(
child: Text('300 x 200'),
onPressed: () {},
),
),
));
}
Use Media Query to use width wisely for your solution which will run the same for small and large screen
Container(
width: MediaQuery.of(context).size.width * 0.5, // Will take 50% of screen space
child: RaisedButton(
child: Text('Go to screen two'),
onPressed: () => null
),
)
You can apply a similar solution to SizeBox also.
My preferred way to make Raise button with match parent is that wrap it with Container.
below is sample code.
Container(
width: double.infinity,
child: RaisedButton(
onPressed: () {},
color: Colors.deepPurpleAccent[100],
child: Text(
"Continue",
style: TextStyle(color: Colors.white),
),
),
)
This piece of code will help you better solve your problem, as we cannot specify width directly to the RaisedButton, we can specify the width to it's child
double width = MediaQuery.of(context).size.width;
var maxWidthChild = SizedBox(
width: width,
child: Text(
StringConfig.acceptButton,
textAlign: TextAlign.center,
));
RaisedButton(
child: maxWidthChild,
onPressed: (){},
color: Colors.white,
);
Simply use FractionallySizedBox, where widthFactor & heightFactor define the percentage of app/parent size.
FractionallySizedBox(
widthFactor: 0.8, //means 80% of app width
child: RaisedButton(
onPressed: () {},
child: Text(
"Your Text",
style: TextStyle(color: Colors.white),
),
color: Colors.red,
)),
You can create global method like for button being used all over the app. It will resize according to the text length inside container. FittedBox widget is used to make widget fit according to the child inside it.
Widget primaryButton(String btnName, {#required Function action}) {
return FittedBox(
child: RawMaterialButton(
fillColor: accentColor,
splashColor: Colors.black12,
elevation: 8.0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 13.0),
child: Center(child: Text(btnName, style: TextStyle(fontSize: 18.0))),
),
onPressed: () {
action();
},
),
);
}
If you want button of specific width and height you can use constraint property of RawMaterialButton for giving min max width and height of button
constraints: BoxConstraints(minHeight: 45.0,maxHeight:60.0,minWidth:20.0,maxWidth:150.0),
If you want globally change the height and the minWidth of all your RaisedButtons, then you can override ThemeData inside your MaterialApp:
#override
Widget build(BuildContext context) {
return MaterialApp(
...
theme: ThemeData(
...
buttonTheme: ButtonThemeData(
height: 46,
minWidth: 100,
),
));
}
Wrap RaisedButton inside Container and give width to Container Widget.
e.g
Container(
width : 200,
child : RaisedButton(
child :YourWidget ,
onPressed(){}
),
)
We can also use ElevatedButton Widget, it have fixedSize property. latest Flutter version
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
fixedSize: Size(120, 34), // specify width, height
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
20,
))),
child: Text("Search"),
)
Preview
This worked for me. The Container provides the height and FractionallySizedBox provides the width for the RaisedButton.
Container(
height: 50.0, //Provides height for the RaisedButton
child: FractionallySizedBox(
widthFactor: 0.7, ////Provides 70% width for the RaisedButton
child: RaisedButton(
onPressed: () {},
),
),
),
Try with Container, I think we will have more control.
ElevatedButton(
style: ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20)),
onPressed: () {
buttonClick();
},
child: Container(
height: 70,
width: 200,
alignment: Alignment.center,
child: Text("This is test button"),
),
),
you can do as they say in the comments or you can save the effort and work with RawMaterialButton . which have everything and you can change the border to be circular
and alot of other attributes. ex shape(increase the radius to have more circular shape)
shape: new RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),//ex add 1000 instead of 25
and you can use whatever shape you want as a button by using GestureDetector which is a widget and accepts another widget under child attribute.
like in the other example here
GestureDetector(
onTap: () {//handle the press action here }
child:Container(
height: 80,
width: 80,
child:new Card(
color: Colors.blue,
shape: new RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
elevation: 0.0,
child: Icon(Icons.add,color: Colors.white,),
),
)
)
If the button is placed in a Flex widget (including Row & Column), you can wrap it using an Expanded Widget to fill the available space.
we use Row or Column, Expanded, Container and the element to use example RaisedButton
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
),
Row(
children: <Widget>[
Expanded(
flex: 2, // we define the width of the button
child: Container(
// height: 50, we define the height of the button
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: RaisedButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Colors.white,
color: Colors.blue,
onPressed: () {
// Method to execute
},
child: Text('Copy'),
),
),
),
),
Expanded(
flex: 2, // we define the width of the button
child: Container(
// height: 50, we define the height of the button
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: RaisedButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Colors.white,
color: Colors.green,
onPressed: () {
// Method to execute
},
child: Text('Paste'),
),
),
),
),
],
),
],
),
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
child: Text("FULL WIDTH"),
onPressed: () {},
),
),
Use ElevatedButton since RaisedButton is deprecated
In my case(the Button is a child of a horizontal ListView), I had to wrap the button with a padding widget and set right/left padding.
Padding(
padding: const EdgeInsets.only(right: 50, left: 50),
child: ElevatedButton(onPressed: () {}, child: Text("LOGOUT")),
)
In my case I used margin to be able to change the size:
Container(
margin: EdgeInsets.all(10),
// or margin: EdgeInsets.only(left:10, right:10),
child: RaisedButton(
padding: EdgeInsets.all(10),
shape: RoundedRectangleBorder(borderRadius:
BorderRadius.circular(20)),
onPressed: () {},
child: Text("Button"),
),
),
If you don't want to remove all the button theme set up.
ButtonTheme.fromButtonThemeData(
data: Theme.of(context).buttonTheme.copyWith(
minWidth: 200.0,
height: 100.0,,
)
child: RaisedButton(
onPressed: () {},
child: Text("test"),
),
);
If you have a button inside a Column() and want the button to take maximum width, set:
crossAxisAlignment: CrossAxisAlignment.stretch
in your Column widget. Now everything under this Column() will have maximum available width
I struggled with this problem and found what my problem was: I defined all my buttons inside a ListView. Does not matter what I did, the width of the button was always the width of the screen. I replaces ListView by Column and voila - suddenly I could control the button width.
Use SizeBox with width and height parameters
SizedBox(
width: double.infinity,
height: 55.0,
child: ElevatedButton(
.....
),
);
You don't need to use other widget to set the size. You can use minimumSize for ElevatedButton
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(200, 50),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50), // <-- Radius
),
),
onPressed: (){},
child: const Text("Text", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),),
),
To set the height and width of Any Button Just Wrap it with SizedBox. you set easily the height and width of any button by Wrape with SizedBox .
And if you want to give Space between Two Any Kind of Widgets then you can Used SizedBox and inside the SizedBox you use height .As much as you want to give..
wrap your ElevatedButton with a Column PLUS add padding for the button for the style:
Column(
children: [
ElevatedButton(
style: TextButton.styleFrom(
backgroundColor: Colors.green,
padding: const EdgeInsets.symmetric(
horizontal: 20 * 1.5, vertical: 20),
),
onPressed: () {},
child: const Text('text')),],),