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

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

Related

Flutter - How to make the first element of a dynamic list fixed (unscrollable) at top?

PopupMenuButton<String>(
///Icon
child: SizedBox(
child: Stack(
children: [
const Icon(
Icons.notifications_outlined,
),
Container(
child: Container(
child: Padding(
padding: const EdgeInsets.all(0.0),
child: Center(
child: Text(
''
),
),
),
),
)
],
),
),
onSelected: (value) {},
itemBuilder: (BuildContext context) {
///generating list on the fly
var myList = someList!.map((listItem) {
return PopupMenuItem<String>(
value: listItem.id.toString(),
child: SizedBox(
child: Column(
children: [
Text(
listItem.name!,
),
],
),
),
);
}).toList();
var closeButtonList = [
PopupMenuItem<String>(
child: Column(
children: [
Align(
alignment: Alignment.centerRight,
child: IconButton(
onPressed: Navigator.of(context).pop,
icon: const Icon(
Icons.close,
),
),
),
],
),
),
///appending list using spread operator
...myList
];
return closeButtonList;
},
This code works fine and displays a cross(close) icon as the first element of the list.
The problem is when I scroll the list, the icon get scrolled and disappears from the screen.
How can I make it fixed while the rest of the list is scrollable?

Images don't displayed on screen

I have modified my code. I thought I could achieve what I am willing to do but I am still having an issue. The first image is fine, but when I am adding more images, they don't display to the screen. The idea is to allow the user to click on a button to select one or several images. Then, he can tap on a second button and add one pfd file, it is like adding attachment in email.Then, if the user wants he can tap on the first button and add an other image. The list of all the documents should be displayed on the screen. I though that maybe a set State is missing somewhere. Here is the code. I do not understand where is my mistake. Thank you in advance.
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
List<PlatformFile>? _paths;
List<String> filesGB =[];
bool _loadingPath = false;
String fileExtension='';
String _fileName='';
// To access the pictures
void _openPictureFileExplorer() async {
setState(() => _loadingPath = true);
try {
_paths = (await FilePicker.platform.pickFiles(
type: FileType.media,
allowMultiple: true,
))?.files;
if (_paths != null) {
_paths!.forEach((element) {
filesGB.add(element.path.toString());
print(filesGB);
print(filesGB.length);
});
setState(() {
});
}
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
//#############
//Display card with button to select type of document
child: Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//Attachement
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.attach_file),
Text('Attachment'),
],
)
),
onTap: () async {
fileExtension = 'pdf';
_openDocumentFileExplorer();
},
),
),
//Photo
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {
fileExtension = 'jpeg';
_openPictureFileExplorer();
},
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: filesGB.isNotEmpty ?
Column(
children: listOfCards(filesGB),
)
:Text('Nothing to display'),
),
]),)))));
}
}
List<Widget> listOfCards(List<String> item){
List<Widget> list = <Widget>[];
ListView.builder(
itemCount: filesGB.length,
itemBuilder: (BuildContext ctxt, int index) {
return new Container(
height: 114,
child: GestureDetector(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113, width: 113,
child: Image.file(File(item[i].toString()),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(item[i]
.split('/')
.last),
),
),
],
),
),),
),
);
});
return list;
}
first of all, you don't need to use for loop for building your pictures list
just use ListView.builder
but about your problem, I think it happens because you set selected pictures in a row
then return that row as a child of your column
so your pictures align horizontally and column just show widgets in vertical aligns
in other words, your column just have one child, and its a Row
so column just show pictures as possible then you just see the first picture.
for solving this problem you should return a list of widgets in the listOfCards function
just do these simple changes and I hope your problem solved
change your function return parameter to List<Widget>
Widget listOfCards(List<String> item) {
to
List<Widget> listOfCards(List<String> item) {
then just return your list
return list;
and your column should look like this
Column(
children: listOfCards(filesGB),
)
I have find a working solution. It does what I was expecting with image. I still have a problem when I delete a record, the card is not removed. I do not find where I should use the setState. I will continue to investigate.
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
//#############
//Display card with button to select type of document
child: Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//Attachement
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.attach_file),
Text('Attachment'),
],
)
),
onTap: () async {
fileExtension = 'pdf';
_openDocumentFileExplorer();
},
),
),
//Photo
FlatButton(
onPressed: () {},
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment
.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {
fileExtension = 'jpeg';
_openPictureFileExplorer();
},
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: filesGB.isNotEmpty ?
Column(
children: getList(),//[listOfCards(filesGB)],
)
:Text('Nothing to display'),
),
]),)))));
}
}
List<Widget> getList() {
List<Widget> childs = [];
for (var i = 0; i < filesGB.length; i++) {
childs.add(
GestureDetector(
onTap: (){
print ("Pressed");
},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113,width: 113,
child: fileExtension == 'pdf'?
Image.asset('assets/logo_pdf.png',
// fit: BoxFit.fill,
// width: double.infinity,
):
Image.file(File(filesGB[i].toString()),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(filesGB[i].toString().split('/').last,//_nameOfFile,//name,
style: TextStyle(fontWeight: FontWeight.bold),),
),
),
Padding(
padding: const EdgeInsets.only(right:25.0),
child: IconButton(onPressed: (){
//delete a record and the card displaying this record
// Delete the selected image
// This function is called when a trash icon is pressed
if (filesGB.length > 1) {
filesGB.removeAt(i);
print(filesGB);
setState(() {});
}
},
icon:Icon (Icons.delete, color: Colors.red,),),
)
],
),
),
//subtitle: Text(path),
),
));}
return childs;
}

Flutter Form Field floating at the top

I am having an issue with flutter forms.
Basically I have 3 simple rows added to a Stack. The last one contains a form. Below that there are 'Pinned' elements by Adobe XD, but the row containing the form is floating at the top of the screen... I would expect it to be arranged below the two first rows.
You can see the issue in the screenshot below. The form is on top of the image, but I want it to be above the 2 white lines which I want to replace by functional form fields.
Where am I going wrong? I have put the form in a separate Widget.
LoginPage.dart
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
stops: [
0.4,
1
],
colors: [
Colors.black,
Color(0xff7d060b),
])),
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: SafeArea(
child: Stack(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
/* Image.asset(
'assets/images/Logo.png',
height: 100,
width: 250,
),*/
Image.asset(
'assets/images/fewturelogo.png',
height: 50,
),
Container(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
color: Colors.white,
icon: const Icon(Icons.not_listed_location_rounded),
onPressed: () {
print('Hello');
showDialog(
context: context,
barrierDismissible: false,
// user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Was ist Rentalsplanet?'),
content: new SingleChildScrollView(
child: new ListBody(children: [
new Text(
'Hier erscheinen Informationen über Rentalsplanet')
]),
),
actions: [
new ElevatedButton(
child: Text('Alles klar!'),
onPressed: () {
Navigator.of(context).pop();
})
],
);
});
},
)),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.only(top: 70.0),
child: Image.asset(
'assets/images/SplashImageLogin.png',
scale: 1.1,
),
),
],
),
Row(children: [
Container(
margin: const EdgeInsets.only(top: 70.0),
child: SizedBox(width: 100, child: LoginForm()),
)
]),
],
),
),
),
);
LoginForm.dart
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
children: <Widget>[
new Flexible(
child: TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
),
ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
// Add TextFormFields and ElevatedButton here.
],
),
);
}
because you are using stack... stack is not an easy thing to work with and in your case, if you don't have to use it replace it with Column and your problem will be fixed.
if not alignment in Stack or fractionaloffset or Transform.translate will help you
Transform.translate will fix your problem but it might cause some responsive issues

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

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...)
//...
)

track which container was clicked on in flutter

I have 3 containers and in each picture, when you click on which an icon appears. How to assign a value to each container, so that when you click it, you can change it too. Or how to track which container was clicked on
class _EditAccountScreenState extends State<EditAccountScreen> {
bool checkboxValue = false;
...
child: GestureDetector(
onTap: () {
setState(() {
checkboxValue = !checkboxValue;
});
},
child: Padding(
child: Row(
children: <Widget> [
Container(
child: Stack(
children: <Widget>[
Image.asset('assets/images/telegram-512.png',fit: BoxFit.fill),
Positioned(
bottom: 0, right: 15, //give the values according to your requirement
child: checkboxValue
? Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius:BorderRadius.circular(100)
),
child: Icon(
Icons.check,
color: Colors.white,
size: 15,
)
)
: Container(),),],),),
Container(
child: Stack(
children: <Widget>[
Image.asset('assets/images/Viber-Logo.png',fit: BoxFit.fill),
Positioned(
bottom: 0, right: 15, //give the values according to your requirement
child: checkboxValue
? Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius:BorderRadius.circular(100)
),
child: Icon(
Icons.check,
color: Colors.white,
size: 15,
)
)
: Container(),),],),),
Use Gesture Detector to detect Taps on containers.
Here is an example related to this:
Container(
alignment: FractionalOffset.center,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.lightbulb_outline,
color: _lights ? Colors.yellow.shade600 : Colors.black,
size: 60,
),
),
GestureDetector(
onTap: () {
setState(() {
_lights = true;
});
},
child: Container(
color: Colors.yellow.shade600,
padding: const EdgeInsets.all(8),
child: const Text('TURN LIGHTS ON'),
),
),
],
),
)
First of All Make a Integer Variable and then set its value to -1 by default
int selectedContainerIndex = -1;
Now, You Can Wrap each of your Container in seperate GestureDetector, and then on the onTap method you can set the selectedContainerIndex value of your container according to you.
See the below Code
Stack(
children: [
//First Container
GestureDetector(
onTap: () {
selectedContainerIndex = 0;
setState(() {});
},
child: new Container(),
),
//Second Container
GestureDetector(
onTap: () {
selectedContainerIndex = 1;
setState(() {});
},
child: new Container(),
),
//Third Container
GestureDetector(
onTap: () {
selectedContainerIndex = 2;
setState(() {});
},
child: new Container(),
),
],
),
Now To know which Container was tapped you can always use the selectedContainerIndex Value
print(selectedContainerIndex);
NOTE: If your containers are more in numbers say 4 or 5, then I would recommend you to use good practice and show those using some dynamic listview builder, instead of hardcoding them each.