I am trying to displayed time selected from showTimePicker dialogue but after getting the value it becomes null again.
after debugging, it seems like the value returned from future function expried or something.
after the widgets onPress function it is back to null.
ElevatedButton(
child: const Text('Time'),
onPressed: () async {
vTimeSelected = await getTimeSelected(context);
setState(() {
// vStrToRndr = vTimeSelected.toString();
//print(vStrToRndr);
});
},
),
ElevatedButton(
child: const Text('Solid'),
onPressed: () {
setState(() {
vDetail.solid = !vDetail.solid;
});
},
),
],
),
),
if (vDetail.wet == true) Text('Nappy wet'),
if (vDetail.solid == true) Text('Nappy Solid'),
Text('Time: $vTimeSelected'),
[7:35 PM]
Future<TimeOfDay?> getTimeSelected(BuildContext context) async {
TimeOfDay vTime = TimeOfDay(hour: 0, minute: 0);
TimeOfDay? newTime =
await showTimePicker(context: context, initialTime: vTime);
return newTime;
//print($newTime);
}
//thanks for any help
Text('Time: $vTimeSelected') //<---- this is displaying null
You can follow this code structure. Make sure to declare variable outside the build method.
class TS extends StatefulWidget {
const TS({super.key});
#override
State<TS> createState() => _TSState();
}
class _TSState extends State<TS> {
TimeOfDay? vTimeSelected;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () async {
vTimeSelected = await getTimeSelected(context);
setState(() {});
}),
body: Text("${vTimeSelected}"),
);
}
}
Related
Created a demo for understanding future..
I have taken two screen....Using Future.delayed I am forwarding to next screen in 5 seconds with CircularProgressIndicator...but when I move to back..it still showing CircularProgressbar...
What should I correct my code?
here is my code
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
bool isloading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Async demo'),
),
body: isloading == true
? Center(child: CircularProgressIndicator())
: Center(
child: TextButton(
child: Text('Pressed'),
onPressed: () {
setState(() {
isloading = true;
});
Future.delayed(Duration(seconds: 5), () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return NextScreen();
}));
isloading = false;
});
},
),
),
);
}
}
What should I correct my code?
Wrap the second assignment of isloading to false inside setState (just as you did when setting to true). Something like the following:
onPressed: () {
setState(() {
isloading = true;
});
Future.delayed(Duration(seconds: 5), () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return NextScreen();
}));
setState(() {
isloading = false;
});
});
},
you need to use setState when you are assign variable = false
For that do as below
replace this
isloading = false;
with
setState(() {
isloading = false;
});
I'm trying to add one alert box for language selection, but couldn't figure out the builder error I'm facing.
it was working fine with flutter older version but not with 2.2.3 version of flutter
Thanks
for the help
Looking forward for the solution
The named parameter 'builder' is required, but there's no corresponding argument.
The named parameter 'child' isn't defined.
Undefined name 'Utils'.
Future <void> _languageCheck() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final firstRun = prefs.getBool("firstRunLanguage");
(firstRun ?? false)
? () {}
: await showDialog(
barrierDismissible: false,
context: context,
child: AlertDialog(content: LanguageDialog()));
await prefs.setBool('firstRunLanguage', true);
}
Widget
class LanguageDialog extends StatefulWidget {
#override
_LanguageDialogState createState() => _LanguageDialogState();
}
class _LanguageDialogState extends State<LanguageDialog> {
var langCode = "en";
void getLanguage() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
langCode = prefs.getString("language") ?? kAdvanceConfig['DefaultLanguage'];
printLog("langCode-->$langCode");
setState(() {});
}
#override
void initState() {
super.initState();
getLanguage();
}
#override
Widget build(BuildContext context) {
List<Widget> list = [];
List<Map<String, dynamic>> languages = Utils.getLanguagesList(context);
for (var i = 0; i < languages.length; i++) {
// if (langCode == languages[i]["code"]) {
// print(languages[i]["code"]);
// }
list.add(
ListTile(
leading: Image.asset(
languages[i]["icon"],
width: 30,
height: 20,
fit: BoxFit.cover,
),
title: Text(languages[i]["name"]),
trailing: langCode == languages[i]["code"]
? const Icon(
Icons.radio_button_checked,
color: Colors.teal,
)
: const Icon(
Icons.radio_button_off,
color: Colors.teal,
),
onTap: () async {
setState(() {
langCode = languages[i]["code"];
});
await Provider.of<AppModel>(context, listen: false)
.changeLanguage(languages[i]["code"], context);
},
),
);
if (i < languages.length - 1) {
list.add(
Divider(
color: Theme.of(context).primaryColorLight,
height: 1.0,
indent: 75,
//endIndent: 20,
),
);
}
}
return SingleChildScrollView(
child: Column(
children: [
...list,
const LinearProgressIndicator(),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("OK")),
],
),
);
}
}
showDialog doesn't have child, use its builder like
await showDialog(
barrierDismissible: false,
context: context,
builder: (context) => // here
AlertDialog(content: LanguageDialog()))
More on showDialog
You used showDialog() method which has a required parameter caller builder so you must provide the builder argument so try like below
Future <void> _languageCheck(BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final firstRun = prefs.getBool("firstRunLanguage");
(firstRun ?? false)
? () {}
: await showDialog(
barrierDismissible: false,
context: context,
/// this builder parameter is required
builder:(context) => AlertDialog(content: LanguageDialog()));
await prefs.setBool('firstRunLanguage', true);
}
I am trying to display an information dialog when starting an application. After closing, another window appears asking for permission. I call it all in the initState function. It works, but I noticed that this first info dialog also closes on its own when 15 seconds have elapsed. How do I fix this? So that while the dialog is not closed by the user, the application will not be loaded further?
class _MyAppState extends State<MyApp> {
final keyIsFirstLoaded = 'is_first_loaded';
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final context = MyApp.navKey.currentState.overlay.context;
await showDialogIfFirstLoaded(context);
await initPlatformState();
});
}
showDialogIfFirstLoaded(BuildContext context, prefs) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool(keyIsFirstLoaded);
if (isFirstLoaded == null) {
return showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return new AlertDialog(
// title: new Text("title"),
content: new Text("//"),
actions: <Widget>[
new FlatButton(
child: new Text(".."),
onPressed: () {
Navigator.of(context).pop();
prefs.setBool(keyIsFirstLoaded, false);
},
),
],
);
},
);
}
}
initPlatformState() async {
print('Initializing...');
await BackgroundLocator.initialize();
print('Initialization done');
final _isRunning = await BackgroundLocator.isRegisterLocationUpdate();
setState(() {
isRunning = _isRunning;
});
onStart();
print('Running ${isRunning.toString()}');
}
#override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
// ... app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
navigatorKey:MyApp.navKey,
navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics),
],
debugShowCheckedModeBanner: false,
title: '',
theme: ThemeData(),
home: new SplashScreen(),}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
Timer _timer;
bool _visible = true;
startTime() async {
_timer = Timer(new Duration(seconds: 5), navigationPage);
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/home');
}
#override
void initState() {
_timer = Timer(Duration(seconds: 4),
() => setState(
() {
_visible = !_visible;
},
),
);
startTime();
super.initState();
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Image.asset('images/bg.jpg',
fit: BoxFit.cover,
height: 1200,
),
),
Container(
width: double.infinity,
height: 1200,
color: Color.fromRGBO(0, 0, 0, 0.8),
),
Container(
alignment: Alignment.center,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Text(''),
),
),
],
),
),
],
);
}
}
This code displays an Alert dialogue if the user is new and after the button click, it will direct him to another dialogue.
I have tested the code and it doesn't close after 15 seconds. I'm still not sure what you're trying to accomplish but I hope this helps.
Init State
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await dialog1(context);
//await initPlatformState();
});
super.initState();
}
Alert Dialog 1
dialog1(BuildContext context)async{
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool("keyIsFirstLoaded")??true;
if (isFirstLoaded) {
showDialog(
barrierDismissible: false, //disables user from dismissing the dialog by clicking out of the dialog
context: context, builder: (ctx) {
return AlertDialog(
title: Text("dialog 1"), content: Text("Content"), actions: [
TextButton(
child: new Text(".."),
onPressed: () async{
Navigator.pop(ctx);
await dialog2(context);
prefs.setBool("keyIsFirstLoaded", false);
},
),],);
},);
}else{
//not first time
}
}
Alert Dialog 2
void dialog2(BuildContext context)async{
print("dialog 2");
showDialog(context: context, builder: (context) {
return AlertDialog(title: Text("Dialog 2"),content: Text("permissions"),actions: [
TextButton(
child: new Text("close"),
onPressed: () async{
Navigator.pop(context);
//await dialog1(context); //uncomment if you want to go back to dialoge 1
},
),],);
},);
}
You can return a value from Navigator in the first dialog
Navigator.of(context).pop(true);
prefs.setBool(keyIsFirstLoaded, false);
Once it receive true, then only call the second method.
var value = await showDialogIfFirstLoaded(context);
if(value == true) {
await initPlatformState();
}
I am using showTimePicker to get the time from a user. I can get the time as much as I like and assign it to a variable time. The problem is, there will be many instances in my code where I want to get the time but make it a whole new variable, time2 or time3 or whatever. In my code, whenever I call the the function selectTime() it will only ever set the value for the one variable time. I also am not sure how it affects timeOfDay picked;. I could get round these problems by writing a new selectTime() function for each variable but that seems like terrible progrmming.
How can I change my code so that it is possible to assign a new time to any variable without changing the time of others. I am quite new to flutter and will appreciate any help.
Bellow is my code. Of course I'll have another raised button used for changing time2.
Cheers
import 'dart:async';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Troponin Algorithm',
home: CustomForm(),
);
}
}
class CustomForm extends StatefulWidget {
#override
_CustomFormState createState() => _CustomFormState();
}
class _CustomFormState extends State<CustomForm> {
timeFormatter(number) {
//String str;
if (number > 9) {
return number.toString();
}
else {
//str = '0'+number.toString();
return '0'+number.toString();
}
}
TimeOfDay time = TimeOfDay.now();
TimeOfDay time2 = TimeOfDay.now();
TimeOfDay picked;
String hour;
String mins;
String hour2;
String mins2;
Future<Null> selectTime(BuildContext context) async {
picked = await showTimePicker(
context: context,
initialTime: time,
);
if (picked != null) {
setState(() {
time = picked;
});
}
}
#override
Widget build(BuildContext context) {
mins = timeFormatter(time.minute);
hour = timeFormatter(time.hour);
//mins2 = timeFormatter(time2.minute);
return Scaffold(
appBar: AppBar(
title: Text('Troponin Algorthm')
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text('time is $hour:$mins'), //'${_time.hour}:${_time.minute}'
),
RaisedButton(
child: Text('change time'),
onPressed: () {
setState(() {
selectTime(context);
});
}
),
],
),
Text('time1 is: $time'),
],
)
);
}```
Instead of selectTime returning a Future<Null>, you could modify it to return a Future<TimeOfDay>. The docs specify that showTimePicker will return a Future<TimeOfDay> based on the user's selection or null if the user cancels the dialog.
Future<TimeOfDay> selectTime(BuildContext context) async {
picked = await showTimePicker(
context: context,
initialTime: time,
);
return picked;
}
And change your RaisedButton like this:
RaisedButton(
child: Text('change time'),
onPressed: () async {
// We wait for either a Future<TimeOfDay> or a null
var temp = await selectTime(context) ;
if (temp != null) {
setState(() {
time = temp;
});
}
},
),
I a trying to pass a Value from when a button is clicked, What I want in the code is to pass the value from the Button Widget to another Page's Variable named pdfNo. Here's my code:
FlatButton(
padding: EdgeInsets.fromLTRB(2, 5, 5, 5),
child: ListTile(
leading: Icon(Icons.book, color: Color(0xFFEB3549)),
title: Text('Book5'),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PDFPage() ));
print('Pressed 6');
},
),`
This is the Button on the First Page , On Pressed I would like to pass a Value to a function which is child, so I have created a variable , but cant figure out how to go about this next:
var pdfNo = 2;
bool _isLoading = true;
PDFDocument document;
#override
void initState() {
super.initState();
changePDF(pdfNo);
loadDocument();
}
changePDF(value) async {
setState(() => _isLoading = true);
if (value == 1) {
document = await PDFDocument.fromAsset('assets/sample2.pdf');
} else if (value == 2) {
document = await PDFDocument.fromURL(
"http://conorlastowka.com/book/CitationNeededBook-Sample.pdf");
} else {
document = await PDFDocument.fromAsset('assets/sample.pdf');
}
setState(() => _isLoading = false);
}
So, I would like to pass a int from the button on page 1 Staleful Class to a Stateful Class on second page to changePDF(here).
Please help me out. PS New to Flutter,Dart
You can create a to arguments...
Something like this
class LoginWidgetArguments {
final String username;
LoginWidgetArguments(
{this.username});
}
class LoginWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _LoginWidgetState();
}
class _LoginWidgetState extends State<LoginWidget>{
LoginWidgetArguments args;
#override
void initState() {
//Get context
// I do this because sometimes it doesn't get the context without the FutureDelay... This workaround I used with the first flutter versions, maybe now its not needed
Future.delayed(Duration.zero, () {
args = ModalRoute.of(context).settings.arguments;
if (args != null) {
print(args.username)
}
});
}
....
}
And to navigate
Navigator.pushNamed(context, LoginPage.routeName,
arguments: LoginWidgetArguments(
user: "user#yay.com");
Edit
Maybe it could be simple...
FlatButton(
padding: EdgeInsets.fromLTRB(2, 5, 5, 5),
child: ListTile(
leading: Icon(Icons.book, color: Color(0xFFEB3549)),
title: Text('Book5'),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PDFPage(pageNumber: 6) ));
print('Pressed 6');
},
)
class PDFPage extends StatefulWidget {
final int pageNumber;
PDFPage({this.pageNumber});
#override
_PDFPageStage createState() => _PDFPageStage();
}
class _PDFPageStage extends State<PDFPage> {
...
#override
void initState() {
super.initState();
changePDF(widget.pageNumber);
loadDocument();
}
...
}
I'm not sure if I understand the problem correctly, but I think you can pass the number to the constructor of the StatefulWidget. I changed the PDFDocument to a String for simplicity.
Some button press on first page:
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PDFPage(pdfNo: 4),
),
);
},
The second page:
class PDFPage extends StatefulWidget {
final int pdfNo;
const PDFPage({Key key, this.pdfNo}) : super(key: key);
#override
_PDFPageState createState() => _PDFPageState();
}
class _PDFPageState extends State<PDFPage> {
bool _isLoading = false;
String _document;
void changePDF(int value) async {
setState(() => _isLoading = true);
if (value == 1) {
_document = await Future.delayed(Duration(seconds: 1), () => 'Value 1');
} else if (value == 2) {
_document = await Future.delayed(Duration(seconds: 1), () => 'Value 2');
} else {
_document = await Future.delayed(Duration(seconds: 1), () => 'Other value');
}
setState(() => _isLoading = false);
}
#override
void initState() {
super.initState();
changePDF(widget.pdfNo);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test'),),
body: Center(
child: _isLoading ? CircularProgressIndicator() : Text(_document ?? '(null)'),
),
);
}
}