Control on tap ripple effect on Flutter ElevatedButton - flutter

Question
How can I change the duration and colour of the on tap ripple effect on an ElevatedButton? See the dart pad link for a working example of this ripple effect.
Code for working ElevatedButton
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
MyStatelessWidget({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {},
child: const Text('Elevated Button', style: TextStyle(fontSize: 20)),
),
);
}
}
DartPad Link
https://dartpad.dev/369b01f31b06c18d4f47076319aa4da4

It's pretty simple. Just make sure you return your desired overlay color when the current MaterialState is pressed.
Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {},
style: ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith(
(states) {
return states.contains(MaterialState.pressed)
? Colors.red
: null;
},
),
),
child: const Text(
'Elevated Button',
style: TextStyle(fontSize: 20),
),
),
),
),
Better still, you can use this as your buttonStyle:
ElevatedButton.styleFrom(
onPrimary: Colors.yellow,
),
The only problem with this is that it affects your foreground color, but that's not too bad.
So your button with a custom splash should look like this:
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
onPrimary: Colors.yellow,
),
child: const Text(
'Elevated Button',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
Changing the duration of the splash, however, is NOT possible, because, from the source code, the button's splash factory is hardcoded, and not open for modification.
...
splashFactory: InkRipple.splashFactory,
And as this answer shows, you need to modify the splash factory to change the duration.
If you really need that functionality, the quickest way to get that done would be to copy the code from the source and re-implement it yourself. But I wouldn't recommend that.
The more appropriate way you could do this would be to create your own custom button using a Material and an InkWell, but that wouldn't be an elevated button

With Flutter 2.0, try this
ElevatedButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.all<Color>(Colors.black12)),
onPressed: () {},
child: Text('Ripple'))

You can use animationDuration for duration and onPrimary to change splash color.
return ElevatedButton(
onPressed: action,
child:
Text(text, style: Theme.of(context).textTheme.subtitle1),
style: ElevatedButton.styleFrom(
onPrimary: Colors.black,
animationDuration: Duration(milliseconds: 1000),
primary: Colors.red,
shadowColor: Colors.redAccent,
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
);

Related

I can't change my background colour of Textbutton or text in that

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
void main() => runApp(const CustomXylophoneApp());
class CustomXylophoneApp extends StatelessWidget {
const CustomXylophoneApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
TextButton(
onPressed: () {
AudioCache player = AudioCache();
player.play('assets_note1.wav');
TextButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.red);
},
child: Text('Tune1'),
),
You used style in wrong place!
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
backgroundColor: Colors.amber,
),
child: const Text(
'Tune1',
style: TextStyle(color: Colors.black),
),
),
dont use style in void functions like onPressed
You have two option to do that:
ButtonStyle:
TextButton(
onPressed: () {},
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.blue)),
child: Text(
'Tune1',
style: TextStyle(color: Colors.black),
),
),
styleFrom:
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
backgroundColor: Colors.blue,
),
child: Text(
'Tune1',
style: TextStyle(color: Colors.black),
),
),
but I notice that you want to update the background color when play button press, so you can define a variable and when the button pressed change that variable, like this:
Color backgroundColor = Colors.red;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
TextButton(
onPressed: () {
AudioCache player = AudioCache();
player.play('assets_note1.wav');
setState(() {
backgroundColor = Colors.blue;
});
},
style: TextButton.styleFrom(
backgroundColor: backgroundColor,
),
child: Text('Tune1'),
),
....
}

How to Create Elevated Button with Icon and Text in Flutter

How to create a button that has text and an icon by using the latest button widget ElevatedButton.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Elevated Button',
home: FlutterExample(),
);
}
}
class FlutterExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Elevated Button with Icon and Text')),
body: Center(
child: ElevatedButton.icon(
icon: Icon(
Icons.home,
color: Colors.green,
size: 30.0,
),
label: Text('Elevated Button'),
onPressed: () {
print('Button Pressed');
},
style: ElevatedButton.styleFrom(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(20.0),
),
),
)));
}
}
you can add Row() or Wrap() Widget with multiple children in this case Icon() and Text()
ElevatedButton(
onPressed:() {},
child: Wrap(
children: <Widget>[
Icon(
Icons.favorite,
color: Colors.pink,
size: 24.0,
),
SizedBox(
width:10,
),
Text("Click me!", style:TextStyle(fontSize:20)),
],
),
),
You can use ElevatedButton.icon constructor:
ElevatedButton.icon(
onPressed: () {
//OnPressed Logic
},
icon: const Icon(Icons.plus_one),
label: const Text(
"Button Text"
)
),
You can use ElevatedButton.icon constructor for this like
ElevatedButton.icon(
icon: const Icon(Icons.add, size: 18),
label: Text('My elevated button'),
onPressed: () {},
),

Create AppBar as a class flutter

i'm trying to make an appbar as a class for one of my page of my app (only used on 1 page).
I'd like to have addStoryAppBar for my code to be easier to read. How do I do this ? I've tried to create a widget, but it remove the leading back icon
class StoryAddPage extends StatefulWidget {
const StoryAddPage({Key key}) : super(key: key);
#override
_StoryAddPageState createState() => _StoryAddPageState();
}
class _StoryAddPageState extends State<StoryAddPage> {
#override
Widget build(BuildContext context) {
AppBar addStoryAppBar = AppBar(
backgroundColor: Colors.white,
title: Text(
AppLocalizations.of(context).add_story,
style: TextStyle(
color: AppColors.Black,
fontWeight: FontWeight.w700,
fontSize: 16),
),
leading: SvgPicture.asset(
"lib/assets/images/back.svg",
semanticsLabel: 'Back icon',
fit: BoxFit.none,
height: 10,
),
actions: [
GestureDetector(
child: Image.asset('lib/assets/images/select_picture.png'),
onTap: () => {},
),
Padding(
padding: const EdgeInsets.all(10.0),
child: ElevatedButton(
style: kOrangeButton,
onPressed: () => {},
child: Container(
child: Text(
AppLocalizations.of(context).publier,
style: TextStyle(color: AppColors.Black),
),
),
),
),
],
);
return SafeArea(
child: Scaffold(
appBar: addStoryAppBar,
body: Container(
child: Text('Add story'),
),
),
);
}
}
Also tried to extends the AppBar, but how do I pass the context ? Is this the more adapted thing to do ?
class StoryAppBar extends AppBar {
StoryAppBar()
: super(
iconTheme: IconThemeData(
color: Colors.black, //change your color here
),
backgroundColor: Colors.white,
title: Text(
AppLocalizations.of(context).add_story,
style: TextStyle(
color: AppColors.Black,
fontWeight: FontWeight.w700,
fontSize: 16),
),
elevation: 0.0,
automaticallyImplyLeading: false,
actions: <Widget>[
IconButton(
icon: Icon(Icons.notifications),
onPressed: () => null,
),
IconButton(
icon: Icon(Icons.person),
onPressed: () => null,
),
],
);
}
You can extract the AppBar widget to a statefull or stateless widget.
Create your own leading back icon. Just create Text Button, like this:
TextButton.icon(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.arrow_back_rounded),
label: Text(''),
),
Create a separate method that returns AppBar to your screen widget. Add the below method in a new class and call this method from anywhere you want to show AppBar
AppBar getApplicationAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
title: Text(
AppLocalizations
.of(context)
.add_story,
style: TextStyle(
color: AppColors.Black,
fontWeight: FontWeight.w700,
fontSize: 16),
),
leading: SvgPicture.asset(
"lib/assets/images/back.svg",
semanticsLabel: 'Back icon',
fit: BoxFit.none,
height: 10,
),
actions: [
GestureDetector(
child: Image.asset('lib/assets/images/select_picture.png'),
onTap: () => {},
),
Padding(
padding: const EdgeInsets.all(10.0),
child: ElevatedButton(
style: kOrangeButton,
onPressed: () => {},
child: Container(
child: Text(
AppLocalizations
.of(context)
.publier,
style: TextStyle(color: AppColors.Black),
),
),
),
),
],
);
}
If back button functionality not works, then use GestureDetector on Back Button
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: SvgPicture.asset(
"lib/assets/images/back.svg",
semanticsLabel: 'Back icon',
fit: BoxFit.none,
height: 10,
),
),
if you have stateless widget you can Easily implement PreferredSizeWidget
this example show you how do that :
class CustomAppbar extends StatelessWidget implements
PreferredSizeWidget{
const CustomAppbar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container();
}
#override
Size get preferredSize => Size(15.h, 100.w);
}
if you are using StatefulWidget you can copy paste this code
class CustomAppbar extends StatefulWidget implements PreferredSizeWidget {
final bool? isBack;
final TextEditingController? controller;
const CustomAppbar({Key? key, this.isBack, this.controller})
: super(key: key);
#override
State<CustomAppbar> createState() => _CustomAppbarState();
#override
Size get preferredSize => Size(15.h, 100.w);
}
class _CustomAppbarState extends State<CustomAppbar> {
#override
Widget build(BuildContext context) {
return Container()
}
}
and now you can use class on appbar
Scaffold(
appBar: CustomAppbar(
);
the rason for that if you enter to appbar you will see
/// An app bar to display at the top of the scaffold.
final PreferredSizeWidget? appBar;
the app bar is PreferredSizeWidget
and PreferredSizeWidget implement Widget Class
which contain get method
Size get preferredSize;

Change Drawer Icon of Drawer Widget being returned from an external Class

I'm trying to change the icon and color of my drawer widget in Dart. I've found ways of doing it but none that apply to my scenario. My custom drawer widget is being returned from another class and so I can't change the leading icon in the home class where the app bar is or it will replace my current drawer. I won't show all the code because I don't believe it would be necessary. Any help would be appreciated.
My Current drawer and method of calling it:
Drawer class:
import 'package:flutter/material.dart';
import 'package:new_app/Users.dart';
import '../main.dart';
class MainDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
Container(
width: double.infinity,
padding: EdgeInsets.all(20),
color: Theme.of(context).primaryColor,
child: Center(
child: Column(
children: [
Container(
Menu Class/ home page:
import 'screens/drawer_main.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
return new Future(() => false);
},
child: Scaffold(
backgroundColor: Colors.blueGrey[900],
appBar: AppBar(
//backgroundColor: Colors.blueGrey[900],
backgroundColor: Colors.transparent,
automaticallyImplyLeading: true,
title: Text(
"Home Page",
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
//Profile Pic
IconButton(
icon: Icon(Icons.circle, color: Colors.white),
tooltip: 'Comment Icon',
onPressed: () {},
),
MainPopUp(), //IconButton
],
//IconButton
brightness: Brightness.dark,
),
//Current Method of Calling the Drawer:
drawer: MainDrawer(),
body: Center(
Add the leading property in the App Bar and then call the Drawer Widget Programmatically.
Scaffold(
backgroundColor: Colors.blueGrey[900],
appBar: AppBar(
//backgroundColor: Colors.blueGrey[900],
leading: Builder(
builder: (context) => IconButton(
icon: Icon(Icons.menu_rounded),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
backgroundColor: Colors.transparent,
automaticallyImplyLeading: true,
title: Text(
"Home Page",
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
//Profile Pic
IconButton(
icon: Icon(Icons.circle, color: Colors.white),
tooltip: 'Comment Icon',
onPressed: () {},
),
MainPopUp(), //IconButton
],
//IconButton
brightness: Brightness.dark,
),
//Current Method of Calling the Drawer:
drawer: MainDrawer(),
Add a leading inside AppBar() and open drawer programatically.
AppBar(
leading: InkWell(
child: Icon(
//your preferred icon
Icons.camera
),
onTap: () {
Scaffold.of(context).openDrawer();
},
),
)

How to I change the disabled color of an ElevatedButton

I am using Flutter ElevatedButton, which is recommended over RaisedButton in the docs.
In raised button, you could specify and disabledColor. In ElevatedButton, I can not.
How can I stylize what the ElevatedButton looks like when it is disabled?
You can copy paste run full code below
You can use ButtonStyle and check states.contains(MaterialState.disabled) return color you need
In demo code, disabled color is green
code snippet
ElevatedButton(
onPressed: null,
child: Text('Submit disable'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed))
return Theme.of(context)
.colorScheme
.primary
.withOpacity(0.5);
else if (states.contains(MaterialState.disabled))
return Colors.green;
return null; // Use the component's default.
},
),
),
),
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: null,
child: Text('Submit disable'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed))
return Theme.of(context)
.colorScheme
.primary
.withOpacity(0.5);
else if (states.contains(MaterialState.disabled))
return Colors.green;
return null; // Use the component's default.
},
),
),
),
ElevatedButton(
onPressed: () {
print("clicked");
},
child: Text('Submit enable'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed))
return Theme.of(context)
.colorScheme
.primary
.withOpacity(0.5);
else if (states.contains(MaterialState.disabled))
return Colors.green;
return null; // Use the component's default./ Use the component's default.
},
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
A simple solution would be to use onSurface property:
ElevatedButton(
onPressed: null,
style: ElevatedButton.styleFrom(
onSurface: Colors.brown,
),
child: Text('Button'),
)
use onSurface in ElevatedButton.styleFrom
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.white,
onSurface: Colors.green,
),
child: Text("next"),
onPressed:null
)
Try This:
style: ElevatedButton.styleFrom(
disabledBackgroundColor:
Theme.of(context).primaryColor.withOpacity(.8), // Background Color
disabledForegroundColor: Colors.white70, //Text Color
),
Use button's style property. It contains backgroundColor of MaterialStateProperty<Color>. There is a constant MaterialState.disabled. I think this is what you need.
https://api.flutter.dev/flutter/material/MaterialStateProperty-class.html
I created some code to handle disabledText and disabledColor for both FlatButton and RaisedButton with the new TextButton and ElevatedButton widgets.
This gist is here (I couldn't get dartpad to recognize the gist... but you can copy and paste it there directly and it works... it just won't link)
https://gist.github.com/wterrill/7942b4bf5d74a8b2ace952ebf213fe5d
And here's the code itself if you want to copy and paste from here:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final bool disableButton = true; // <-- Change this to see buttons disabled
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
child: Text("FlatButton"),
onPressed: disableButton
? null
: () {
print("FlatButton normal");
},
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
side: BorderSide(color: Colors.purple, width: 3.0)),
disabledColor: Colors.grey,
disabledTextColor: Colors.pink),
SizedBox(height: 25),
FlatButtonX(
childx: Text("TextButton"),
onPressedx: disableButton
? null
: () {
print("FlatButtonX (TextButton)");
},
colorx: Colors.green,
textColorx: Colors.black,
shapex: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
side: BorderSide(color: Colors.purple, width: 3.0)),
disabledColorx: Colors.grey,
disabledTextColorx: Colors.pink),
SizedBox(height: 100),
RaisedButton(
child: Text('RaisedButton'),
color: Colors.green,
textColor: Colors.black,
onPressed: disableButton
? null
: () {
print("RaisedButton normal");
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
side: BorderSide(color: Colors.purple, width: 3.0)),
disabledColor: Colors.grey,
disabledTextColor: Colors.pink,
),
SizedBox(height: 25),
RaisedButtonX(
childx: Text('ElevatedButton'),
colorx: Colors.green,
textColorx: Colors.black,
onPressedx:disableButton
? null
: () {
print("RaisedButtonX (ElevatedButton)");
},
shapex: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
side: BorderSide(color: Colors.purple, width: 3.0)),
disabledColorx: Colors.grey,
disabledTextColorx: Colors.pink,
)
],
),
),
),
);
}
}
Widget FlatButtonX(
{Color colorx,
#required Widget childx,
RoundedRectangleBorder shapex,
#required Function onPressedx,
Key keyx,
Color disabledColorx,
Color disabledTextColorx,
Color textColorx}) {
if (disabledTextColorx == null && textColorx == null) {
disabledTextColorx = colorx;
}
if (textColorx == null) {
textColorx = colorx;
}
return TextButton(
key: keyx,
style: ButtonStyle(
foregroundColor: MaterialStateProperty.resolveWith<Color>(
// text color
(Set<MaterialState> states) => states.contains(MaterialState.disabled)
? disabledTextColorx
: textColorx,
),
backgroundColor: MaterialStateProperty.resolveWith<Color>(
// background color this is color:
(Set<MaterialState> states) =>
states.contains(MaterialState.disabled) ? disabledColorx : colorx,
),
shape: MaterialStateProperty.all(shapex),
),
onPressed: onPressedx as void Function(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0), child: childx));
}
Widget RaisedButtonX(
{Color colorx,
#required Widget childx,
RoundedRectangleBorder shapex,
#required Function onPressedx,
Key keyx,
Color disabledColorx,
Color disabledTextColorx,
Color textColorx}) {
if (disabledTextColorx == null && textColorx == null) {
disabledTextColorx = colorx;
}
if (textColorx == null) {
textColorx = colorx;
}
return ElevatedButton(
key: keyx,
style: ButtonStyle(
foregroundColor: MaterialStateProperty.resolveWith<Color>(
// text color
(Set<MaterialState> states) => states.contains(MaterialState.disabled)
? disabledTextColorx
: textColorx,
),
backgroundColor: MaterialStateProperty.resolveWith<Color>(
// background color this is color:
(Set<MaterialState> states) =>
states.contains(MaterialState.disabled) ? disabledColorx : colorx,
),
shape: MaterialStateProperty.all(shapex),
),
onPressed: onPressedx as void Function(),
child: childx);
}
Because the original disabled color has opacity you can simply wrap it in a container and give the container the color you want. It's a bit hacky but it works and is fast done. Especialy if you have many buttons with different colors.
The cleanest way would be a custom button widget where you can handover the parameters you need.
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(const Radius.circular(radius)),
color: containerColor,
),
width: containerWidth,
height: containerHeight,
child: ElevatedButton(
onPressed: bool ? onPressed : null,
child: Text(
buttonText,
),
),
),
Make all variables nullable which are not allways needed.