Creating model with contains list of widget flutter - flutter

hii i'm a newbie in flutter and now i'm creating screen model(screen_model.dart) like this
class ScreenModel{
final String title;
final Widget screen;
final List<Widget> actions;
ScreenModel({#required this.titleScreen, #required this.widgetScreen, this.actions});
}
then when i try to initialize model in main.dart
final List<Widget> defaultActions = [
IconButton(
icon: Icon(Icons.filter_list, color: Colors.white), onPressed: null),
IconButton(icon: Icon(Icons.add, color: Colors.white), onPressed: null)
];
final List<ScreenModel> _widgetOptions = [
ScreenModel(title: 'Purchasing', screen: PurchasingScreen(),actions: defaultactions)
];
i get an error "The instance member 'defaultActions' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression"
how to fix this?
thanks in advance

You can copy paste run full code below
You can use init _widgetOptions in initState()
List<ScreenModel> _widgetOptions;
#override
void initState() {
_widgetOptions = [
ScreenModel(
title: 'Purchasing',
screen: PurchasingScreen(),
actions: defaultActions)
];
super.initState();
}
working demo
full code
import 'package:flutter/material.dart';
class ScreenModel {
final String title;
final Widget screen;
final List<Widget> actions;
ScreenModel({#required this.title, #required this.screen, this.actions});
}
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> {
final List<Widget> defaultActions = [
IconButton(
icon: Icon(Icons.filter_list, color: Colors.blue), onPressed: null),
IconButton(icon: Icon(Icons.add, color: Colors.blue), onPressed: null)
];
List<ScreenModel> _widgetOptions;
#override
void initState() {
_widgetOptions = [
ScreenModel(
title: 'Purchasing',
screen: PurchasingScreen(),
actions: defaultActions)
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: _widgetOptions[0].actions,
),
),
);
}
}
class PurchasingScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}

Related

Flutter RenderFlex and setState issue while doing buttons and callbacks

Hello I am getting two errors on my code, this code should produce a input box where when the information is submitted via a button it pushes that to the body of the page.
The issues are:
The following assertion was thrown during layout: A RenderFlex
overflowed by 99359 pixels on the bottom.
The following assertion was thrown building TextInputWidget(dirty,
state: _TextInputWidgetState#e5726): setState() or markNeedsBuild()
called during build.
main.dart:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.orange,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String text = "";
void changeText(String text) {
this.setState(() {
this.text = text;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello World!'),
),
body: Column(
children: <Widget>[
TextInputWidget(this.changeText),
Text(this.text),
],
),
);
}
}
class TextInputWidget extends StatefulWidget {
final Function(String) callback;
TextInputWidget(this.callback);
#override
_TextInputWidgetState createState() => _TextInputWidgetState();
}
class _TextInputWidgetState extends State<TextInputWidget> {
final controller = TextEditingController();
#override
void dispose() {
super.dispose();
controller.dispose();
}
click() {
widget.callback(controller.text);
controller.clear();
}
#override
Widget build(BuildContext context) {
return TextField(
controller: this.controller,
decoration: InputDecoration(
prefixIcon: Icon(Icons.message),
labelText: "Type a message.",
suffixIcon: IconButton(
icon: Icon(Icons.send),
splashColor: Colors.orange,
tooltip: "Post message",
onPressed: this.click(),
)));
}
}
The issue is coming from onPressed: this.click(),. It is calling/running the method while first build, but you wish to call it when button is pressed, in this case do it like.
onPressed: click,
If you like to have move things inside onPressed do it like
onPressed: () {
click();
},

How to Change Button text depending on textfield?

enter image description here
Here I want to change the button which depends on a text field, like when the text field is filled then show the button C, and when clicked the C button then change the button name C to AC and also need to change text field fill to empty.
check this example to demonstrate the output you need
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Location',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: const MyHomePage(title: 'Flutter Location Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
String? buttonText;
#override
void initState() {
_controller.addListener(_checkTextIsEmpty);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: Column(
children: [
TextField(
controller: _controller,
onChanged: (value) {},
),
Text(buttonText ?? ''),
],
),
),
);
}
void _checkTextIsEmpty() {
final value = _controller.text.isEmpty ? "AC" : "C";
setState(() {
buttonText = value;
});
}
}

Flutter: How to change the state of a variable in another dart file?

I am currently working on an app; I want to change the value of a String which is declared in another dart file and then pass that changed state to the stateful widget.
I.E;
I create a file called as "Body.dart" file where I have declared a String called as 'scale' who's value initially is "Empty".
Later when a button in another dart file "scale_button" is pressed, I want to assign the string scale = "Hello" in my Body.dart file. So that the stateful widget also displays the same on the screen.
You can use provider(or any other state management) package in that case. In yaml file add, provider: ^4.3.2+4
class HomeApp extends StatefulWidget {
#override
_HomeAppState createState() => _HomeAppState();
}
class _HomeAppState extends State<HomeApp> {
StringProvider _stringProvider;
#override
void initState() {
super.initState();
_stringProvider = Provider.of<StringProvider>(context, listen: false);
}
void updateString() {
_stringProvider.setString('hai');
}
#override
Widget build(BuildContext context) {
StringProvider _stringProvider = Provider.of<StringProvider>(context);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
_stringProvider.str,
style: TextStyle(
fontSize: 22,
),
),
),
RaisedButton(
onPressed: updateString,
child: Text('Click'),
),
],
),
),
);
}
}
// class for storing data(StringProvider.dart)
import 'package:flutter/material.dart';
class StringProvider extends ChangeNotifier { // create a common file for data
String _str = 'hello';
String get str => _str;
void setString(String st) {
_str = st;
notifyListeners();
}
}
When you create a new Flutter project the sample code of the counter shows you how to do this. Check out the comments in the next code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// here is passing a String to MyHomePage.
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
// And here you can see how to make the widget wait for a variable
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Full code of Sample Counter App
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
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>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Show tooltip once page initialized - Flutter

I need to show a hint/tooltip for the userto indicate the user can get his current location by pressing the button. Have included the Tooltip in the code but only when the user does a long press of the button the tooltip is appearing, i want the tooltip to appear when the screen is initialized.
Code:
GlobalKey _toolTipKey = GlobalKey();
GestureDetector(
onTap: () {
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
},
child: Tooltip(
key: _toolTipKey,
message: 'Get current Location',
child: CircleAvatar(
radius: 30,
child: IconButton(
onPressed: getLocation,
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
),
)
I recently had to implement the same thing and I after lot of trying I managed to get it working.
You can use stateful widget and call the function to show tooltip in its initState. Now I got the same error as another person.
The method ensureTooltipVisible was called on null.
To solve this, I had to call
await Future.delayed(Duration(milliseconds: 10));
before ensureTooltipVisible() function.
#override
void initState() {
super.initState();
showTooltipIfOnboadingComplete();
}
and the function to show and close tooltip after certain amount of time,
Future showAndCloseTooltip() async {
await Future.delayed(Duration(milliseconds: 10));
tooltipkey.currentState.ensureTooltipVisible();
await Future.delayed(Duration(seconds: 4));
tooltipkey.currentState.deactivate();
}
you will also have to set you Tooltip widget trigger mode as TooltipTriggerMode.manual,
Here is complete code;
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const FloatingSupportButton()
);
}
}
class FloatingSupportButton extends StatefulWidget {
const FloatingSupportButton({Key? key}) : super(key: key);
#override
State<FloatingSupportButton> createState() => _FloatingSupportButtonState();
}
class _FloatingSupportButtonState extends State<FloatingSupportButton> {
// final GlobalKey<TooltipState> tooltipkey = GlobalKey<TooltipState>();
final tooltipkey = GlobalKey<State<Tooltip>>();
#override
void initState() {
super.initState();
showAndCloseTooltip();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Align(
alignment: Alignment.center,
child: Tooltip(
message: "Hello",
triggerMode: TooltipTriggerMode.manual,
key: tooltipkey,
preferBelow: false,
child: FloatingActionButton(
child: const Icon(Icons.add),
shape: const CircleBorder(
side: BorderSide(
color: Colors.white,
),
),
backgroundColor: const Color(0xFFc60c0c),
onPressed: () {
showAndCloseTooltip();
},
),
),
),
);
}
Future showAndCloseTooltip() async {
await Future.delayed(const Duration(milliseconds: 10));
// tooltipkey.currentState.ensureTooltipVisible();
final dynamic tooltip = tooltipkey.currentState;
tooltip?.ensureTooltipVisible();
await Future.delayed(const Duration(seconds: 4));
// tooltipkey.currentState.deactivate();
tooltip?.deactivate();
}
}
Have a great day everyone, hope this was helpful !!
You should use Statefulwidget and in initState write below code
import 'package:flutter/scheduler.dart';
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// Flutter get callback here when screen initialized.
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
});
}
Here the Full Source code When you run the app it directly shows "Get current Location" tooltip
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key? key, required this.title}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey _toolTipKey = GlobalKey();
#override
void initState() {
super.initState();
SchedulerBinding.instance!.addPostFrameCallback((_) {
// Flutter get callback here when screen initialized.
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Tooltip(
key: _toolTipKey,
message: 'Get current Location',
child: CircleAvatar(
radius: 30,
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
),
],
),
),
);
}
}

Flutter: Widget State: Is this code safe?

The code below is an example to illustrate this question. The code below works, however the following line:
class WidgetCustom extends StatefulWidget {
has "WidgetCustom" underlined in green in vsCode, and when the cursor is positioned over it, it shows the message:
"This class (or a class this class inherits from) is marked as #immutable, but one or more of its instance fields are not final".
The code works fine.
Is it safe to use this code?
Is there a way to achieve this without the warning?
import 'package:flutter/material.dart';
class WidgetCustom extends StatefulWidget {
_WidgetCustomState _state;
WidgetCustom({#required int iCount}) {
_state = _WidgetCustomState(iCount);
}
#override
State<StatefulWidget> createState() {
return _state;
}
int get getIcount => _state.iCount;
}
class _WidgetCustomState extends State<WidgetCustom> {
int iCount;
_WidgetCustomState(this.iCount);
#override
Widget build(BuildContext context) {
return Container(
child: Row(children: <Widget>[
Column(
children: <Widget>[
RaisedButton(
child: const Text("Please tap me"),
onPressed: () {
setState(() => iCount = iCount + 1);
}),
SizedBox(height: 40),
Text("Tapped $iCount Times")
],
),
]));
}
}
Edited to add main.dart
import 'package:flutter/material.dart';
import 'widgetCustom.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Custom Widget Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WidgetCustom _widgetCustom;
String _sMessage = "Fab has not been pressed";
#override
void initState() {
super.initState();
_widgetCustom = WidgetCustom(iCount: 99);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(children: [
_widgetCustom,
SizedBox(height: 40),
Text(_sMessage),
]),
floatingActionButton: FloatingActionButton(
onPressed: _fabPressed,
tooltip: 'Get Value',
child: Icon(Icons.add),
),
);
}
_fabPressed() {
setState(() => _sMessage =
"Value from last button click = ${_widgetCustom.getIcount}");
}
}
Pass the initial value to the constructor when creating the widget as a final value, and then get it from the State class.
Updated code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark(),
home: MyHomePage(title: 'Custom Widget Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
WidgetCustom _widgetCustom;
String _sMessage = "Fab has not been pressed";
int _value = 99;
#override
void initState() {
super.initState();
_widgetCustom = WidgetCustom(iCount: _value, function: _update);
}
void _update(int value) {
setState(() {
_value = value;
_widgetCustom = WidgetCustom(iCount: _value, function: _update);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Column(
children: [
_widgetCustom,
SizedBox(height: 40),
Text(_sMessage),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _fabPressed,
tooltip: 'Get Value',
child: Icon(Icons.add),
),
);
}
_fabPressed() {
setState(() => _sMessage = "Value from last button click = ${_value}");
}
}
class WidgetCustom extends StatefulWidget {
final int iCount;
final Function function;
WidgetCustom({#required this.iCount, this.function});
#override
State<StatefulWidget> createState() {
return _WidgetCustomState();
}
}
class _WidgetCustomState extends State<WidgetCustom> {
int _iCount;
#override
void initState() {
super.initState();
_iCount = widget.iCount;
}
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Column(
children: <Widget>[
RaisedButton(child: const Text("Please tap me"), onPressed: (){
_iCount = _iCount + 1;
widget.function(_iCount);
}),
SizedBox(height: 40),
Text("Tapped $_iCount Times")
],
),
],
),
);
}
}