How can I change the labels of the Continue/Cancel buttons in flutter stepper? - flutter

Is there any way to change the text labels of the Continue and Cancel Buttons of the stepper in flutter? Stepper seems to be the perfect choice for what I want to do (long form with several "stages") and before I go try to build one from scratch just to get other labels for the buttons I thought I may ask..
Anybody knows if/how thats possible?

Yes, you can by providing a controlsBuilder callback. Which has to be a function that takes two other functions (onStepContinue and onStepCancel) which are the actions that you will have to pass to the new buttons you'll create in order for them to act as they should.
Then you can declare anything you want (in this case a row with two buttons) as long you pass the two functions (onStepContinue and onStepCancel) for them to work as its expected:
Stepper(
controlsBuilder: (BuildContext context,
{VoidCallback? onStepContinue, VoidCallback? onStepCancel}) {
return Row(
children: <Widget>[
TextButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
),
TextButton(
onPressed: onStepCancel,
child: const Text('EXIT'),
),
],
);
},
steps: const <Step>[
Step(
title: Text('A'),
content: SizedBox(
width: 100.0,
height: 100.0,
),
),
Step(
title: Text('B'),
content: SizedBox(
width: 100.0,
height: 100.0,
),
),
],
);

flutter version 2.8.1
inside the Stepper you can use controlsBuilder
you can change buttons
controlsBuilder: (context,_) {
return Row(
children: <Widget>[
TextButton(
onPressed: (){},
child: const Text('NEXT'),
),
TextButton(
onPressed: (){},
child: const Text('EXIT'),
),
],
);
},

controlsBuilder: (BuildContext context, ControlsDetails details) {
final _isLastStep = _currentStep == _getSteps.length - 1;
return Container(
margin: const EdgeInsets.only(top: 50),
child: Row(children: [
Expanded(
child: ElevatedButton(
child: Text(_isLastStep ? 'Send' : 'Next'),
onPressed: details.onStepContinue)),
const SizedBox(
width: 12,
),
if (_currentStep != 0)
Expanded(
child: ElevatedButton(
child: Text('Back'),
onPressed: details.onStepCancel))
]));
},

I m late for the discussion.
But i have just done it and think it is good to share.
The code is able to control the Text for each step as the code below.
Each step will have difference text, manage to do for 3 steps. If more than that, the code will be quite messy.
Hope it helps someone who is looking for it.
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
children: <Widget>[
_activeCurrentStep == 0
? TextButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
)
: _activeCurrentStep == 1
? Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
),
TextButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
],
),
)
: _activeCurrentStep >= 2
? Container(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: onStepContinue,
child: const Text('SAVE'),
),
TextButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
],
),
)
: TextButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
],
);
},

Solution for flutter version > 2.8.1
In flutter version > 2.8.1 you can not use this for change the labels or buttons:
controlsBuilder: (context, {onStepContinue, onStepCancel}) {...}
Use this:
controlsBuilder: (context, _) {...}
Or this:
controlsBuilder: (context, onStepContinue) {...}
controlsBuilder: (context, onStepCancel) {...}
This is a complete example changing the labels text and colors:
Stepper(
controlsBuilder: (context, _) {
return Row(
children: <Widget>[
TextButton(
onPressed: () {},
child: const Text(
'NEXT',
style:
TextStyle(color: Colors.blue),
),
),
TextButton(
onPressed: () {},
child: const Text(
'EXIT',
style:
TextStyle(color: Colors.blue),
),
),
],
);
},
//Rest of the Stepper code (currentStep, onStepCancel, onStepContinue, steps...)
//...
)

Related

Flutter Stepper Widget Showing can't be assigned to the parameter type 'Widget Function'

i learn from a youtube ,create Stepper Flutter Tutorial - How To Use Stepper Widget | The Right Way | Multi-Step Forms
controlsBuilder: (context, {onStepContinue, onStepCancel}) {
final isLastStep = currentStep == getSteps().length - 1;
return Container(
margin: EdgeInsets.only(top: 50),
child: Row(
children: [
Expanded(
child: ElevatedButton(
child: Text(isLastStep ? "Confirm" : "NEXT"),
onPressed: onStepContinue,
),
),
const SizedBox(width: 12),
if (currentStep != 0)
Expanded(
child: ElevatedButton(
child: Text("BACK"),
onPressed: onStepCancel,
),
),
],
),
);
},
full code here Github Stepper
keep showing this ..make me confuse can't be assigned to the parameter type 'Widget Function' how to solve this problem ?? thank guy`
You can get onStepCancel and onStepContinue from ControlDetails.
controlsBuilder: (context, details) {
// details.onStepCancel; //you can have it here
// details.onStepContinue
final isLastStep = currentStep == getSteps().length - 1;
return Container(
margin: EdgeInsets.only(top: 50),
child: Row(
children: [
Expanded(
child: ElevatedButton(
child: Text(isLastStep ? "Confirm" : "NEXT"),
onPressed: details.onStepContinue,
),
),
const SizedBox(width: 12),
if (currentStep != 0)
Expanded(
child: ElevatedButton(
child: Text("BACK"),
onPressed: details.onStepCancel,
),
),
],
),
);
},
And try to skip old-tuitorial, better will be following flutter.dev

In Flutter how do I make this Dialog() pop-up box play video, like the AlertDialog()?

My video_player.dart file is working as expected. If I call my VideoPlayerApp() in an AlertDialog() box it works well, but I have few customizable options for the look I need.
body: Center(
child: ElevatedButton(
child: Text("Open Alert Box"),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text("Alert Box"),
content: VideoPlayerApp(),
actions: [
TextButton(
child: Text("Exit"),
onPressed: () => Navigator.pop(context),
),
],
),
);
},
),
),
If I use a Dialog() box to do the same video playback as Flutter documentation suggest (says it can do what the AlertDialog() can do and more), the scene just does the dark shadow back drop over the entire browser content in Chrome and I have to hot start to get out. The box works great if I comment out the VideoPlayerApp(), but with it, a crash without errors. It doesn't work running in the other platforms either (iOS, MacOS, Android). I have played with box sizes and aspect ratio, but same output.
body: Center(
child: Center(
child: ElevatedButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)),
child: SizedBox(
height: 800,
width: 500,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const VideoPlayerApp(),
SizedBox(
width: 220.0,
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text(
"Exit",
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
),
);
});
I appreciate any help making this work, thanks you!!!

flutter: how to customize cuperinoAlertDialog style?

I'm working with flutter. I want to make a CupertinoAlertDialog(iOS style is required). My problem is UI designers require the background color of the alert dialog should be #F0F0F0. But I can only adjust its theme into dark or light(e.g. following picture). The code I completed is placed below.
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return Theme(
data: ThemeData.dark(),
child: CupertinoAlertDialog(
title: Text('Title'),
content: Text('Some message here'),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancle'),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
}
);
Is that possible? Thanks for any advice.
If I recall correctly, the background color for CupertinoAlertDialog is hardcoded. However, you can create a custom dialog that can change the background color of it as well as the functions of the buttons.
You need to create a type Dialog for the showDialog function instead of showCupertinoDialog:
Dialog customDialog = Dialog(
backgroundColor: Color(0xfff0f0f0), // your color
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)), // change 40 to your desired radius
child: CustomAlertDialog(),
);
I also created a stateless widget called CustomAlertDialog, but if you don't want to, you can replace the CustomAlertDialog() with its content.
class CustomAlertDialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 150,
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey, width: 1),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: Center(
child: Text(
"Title",
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
Container(
child: Center(
child: Text("Some message here"),
),
),
],
),
),
),
Expanded(
flex: 1,
child: Row(
children: [
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(color: Colors.grey, width: 1),
),
),
child: Center(
child: Text("Cancel"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
child: Center(
child: Text("OK"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
],
),
),
],
),
);
}
}
Lastly, replace your whole showCupertinoDialog with this showDialog function:
showDialog(
barrierDismissible: true, // set false if you dont want the dialog to be dismissed when user taps anywhere [![enter image description here][1]][1]outside of the alert
context: context,
builder: (context) {
return customDialog;
},
);
Result: https://i.stack.imgur.com/cV13A.png

How to add a FAB using stack when floatingActionButtonLocation is defined?

In my application I have defined a FAB with the property floatingActionButtonLocation set to FloatingActionButtonLocation.centerDocked. I have defined a bottom app bar that holds the centerDocked FAB. I also want to use a Stack widget to position two additional FABs on the top right of the screen. It should look something similar to this - expected result
But when I tried to use a Stack, the FAB which is present in the bottom app bar is displayed but the two FABs under the stack widget are invisible.
docked FAB
FABs under stack widget
code where I have defined the Stack
return new Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: Stack(
children: <Widget>[
Positioned(
// the below values for stack are experimental at the moment
left: MediaQuery.of(context).copyWith().size.width * 0.60,
right: MediaQuery.of(context).copyWith().size.width * 0.01,
// top: MediaQuery.of(context).copyWith().size.height * 0.20,
// bottom: MediaQuery.of(context).copyWith().size.height * 0.7,
child: Row(
children: <Widget>[
// invisible FABs
FloatingActionButton(
onPressed: (){
_animate2Pagenegative();
// print(widget.date);
},
child: Icon(Icons.fast_rewind),
heroTag: UniqueKey(),
),
FloatingActionButton(
onPressed: (){
_animate2Pageforward();
// print(widget.date);
},
heroTag: UniqueKey(),
child: Icon(Icons.fast_forward),
),
],
),
),
// FAB which is displayed correctly
FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () async{
String result1 = await Navigator.push( // string which stores the user entered value
context,
MaterialPageRoute(
builder: (context) => InputScreen(), //screen which has TextField
));
setState(() {
addItem(result1, false, "");
});
},
tooltip: 'Add a task',
child: Icon(Icons.add),
elevation: 0.0,
),
],
),
)
body of Scaffold:
body: new Column(
children: <Widget>[
new Expanded(
child: new DaysPageView(
// onDaysChanged: getDatestring,
physics: new NeverScrollableScrollPhysics(),
dayoverride: getDate(widget.date),
scrollDirection: _scrollDirection,
pageSnapping: _pageSnapping,
reverse: _reverse,
controller: _daysPageController,
pageBuilder: _daysPageBuilder,
),
),
],
),
You don't need other FloatingActionsButtons to do that design. What I understand is that you need the upper part not to scroll with the content hence you thought of FABs. There are multiple ways to achieve that. Here is an example, I'm using colors to show you the different parts of your screen. And of course these are random sizes to show the case.
return new Scaffold(
body: Column(
children: <Widget>[
Container(
height: 150,
color: Colors.red,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20, left: 20),
child: Text(
"- 2 TASKS MORE",
style: TextStyle(
fontSize: 35
),
),
),
GestureDetector(
onTap: () {
print('left arrow pressed');
},
child: Container(
margin: EdgeInsets.only(top: 20, left: 20),
child: Icon(Icons.arrow_left)
),
),
GestureDetector(
onTap: () {
print('right arrow pressed');
},
child: Container(
margin: EdgeInsets.only(top: 20, left: 20),
child: Icon(Icons.arrow_right)
),
)
],
),
SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
children: <Widget>[
Container(
height: 600,
color: Colors.deepPurpleAccent,
),
],
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
],
),
shape: CircularNotchedRectangle(),
color: Colors.red,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: ()
async {
print('FAB pressed');
},
tooltip: 'Add a task',
child: Icon(Icons.add),
elevation: 0.0,
),
);
And here is the result

Loop Cards Flutter

I have been researching Flutter and a question arose --
I have an array with some information, and I need to add cards based on this array.
Currently, I create a loop and add the cards which follow the structure of my array and my program listed below. Note that when I call statement passing the parameters, the code runs without any problem, but the following code does not work for me:
import "package:acessorias/pages/global.variables.dart";
import "package:flutter/material.dart";
class Comunicados extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Center(
child: SizedBox(
width: 150,
child: Image.asset("assets/image/logo.png"),
),
),
actions: <Widget>[
Container(
width: 60,
child: FlatButton(
child: Icon(
Icons.search,
color: Color(0xFFBABABA),
),
onPressed: () => {},
),
),
],
),
body: Container(
color: Color(0xFFF2F3F6),
child: ListView(
children: <Widget>[
comunicado(comunicados[0]["LogNome"], comunicados[0]["EmComDTH"],
comunicados[0]["EmComDesc"]),
comunicado(comunicados[1]["LogNome"], comunicados[1]["EmComDTH"],
comunicados[1]["EmComDesc"]),
comunicado(comunicados[2]["LogNome"], comunicados[2]["EmComDTH"],
comunicados[2]["EmComDesc"]),
comunicado(comunicados[3]["LogNome"], comunicados[3]["EmComDTH"],
comunicados[3]["EmComDesc"]),
comunicado(comunicados[4]["LogNome"], comunicados[4]["EmComDTH"],
comunicados[4]["EmComDesc"]),
comunicado(comunicados[5]["LogNome"], comunicados[5]["EmComDTH"],
comunicados[5]["EmComDesc"])
],
),
),
);
}
}
Widget comunicado(user, data, msg) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text(user),
subtitle: Text(data),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text(msg),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
}
Solution
body: ListView.builder(
itemCount: comunicados.length,
itemBuilder: (context, index) {
/*return ListTile(
title: Text('${comunicados[index]}'),
);*/
return comunicado(comunicados[index]['LogNome'],
comunicados[index]["EmComDTH"], comunicados[index]["EmComDesc"]);
},
),
You can use data model in another dart file like Comunicado.dart
class Comunicado{
String user;
String data;
String msg;
Comunicado(
{this.user, this.data, this.msg});
}
after that you can make list of data model with the static data or etc like
List getComunicado(){
return[
Comunicado(
user: comunicados[0]["LogNome"],
data: comunicados[0]["EmComDTH"],
msg: comunicados[0]["EmComDesc"],
),
Comunicado(
user: comunicados[1]["LogNome"],
data: comunicados[1]["EmComDTH"],
msg: comunicados[1]["EmComDesc"],
),
]
}
in my case, i put it into initial state and don't forget to declare comm
#override
void initState() {
super.initState();
comm= getComunicado();
}
for custom card
Card makeCard(Comunicado newComm) => Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text("${newComm.user}"),
subtitle: Text("${newComm.data}"),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text("${newComm.msg}"),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
and for last you can call make card on listview
ListView.builder(
scrollDirection: Axis.vertical,
itemCount: comm.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(comm[index]);
},
),