I have a Future (async) Date&Time picker function which works fine from within the body of my stateful widget which contains the "Builder" and the function can be called via the onpressed by just this:
onPressed: () {SelectDayAndTimeL();},
Code:
Future _selectDayAndTimeL(BuildContext context) async {
DateTime _selectedDay = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2021),
lastDate: DateTime(2030),
builder: (BuildContext context, Widget child) => child);
TimeOfDay _selectedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (_selectedDay != null && _selectedTime != null) {
//a little check
}
setState(() {
selectedDateAndTime = DateTime(
_selectedDay.year,
_selectedDay.month,
_selectedDay.day,
_selectedTime.hour,
_selectedTime.minute,
);
// _selectedDate = _selectedDay;
});
// print('...');
}
Now I want to be able to call this function from different dart files/screens which means I have to keep this function on a different dart file which I have tried to do, but because of the setState in the function it needs to be inside a stateful widget. I have tried putting it inside a stateful widget but keeps getting errors.
class Picker extends StatefulWidget {
#override
_PickerState createState() => _PickerState();
}
class _PickerState extends State<Picker> {
#override
Future<Widget> build(BuildContext context) async { //the error in on the build on this line
DateTime _selectedDay = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2021),
lastDate: DateTime(2030),
builder: (BuildContext context, Widget child) => child);
TimeOfDay _selectedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (_selectedDay != null && _selectedTime != null) {
//a little check
}
setState(() {
selectedDateAndTime = DateTime(
_selectedDay.year,
_selectedDay.month,
_selectedDay.day,
_selectedTime.hour,
_selectedTime.minute,
);
// _selectedDate = _selectedDay;
});
}
}
How do I properly place the Future Function inside a stateful widget and how to call it on an onpressed?
I don't know if the title I gave this question is actually what it's supposed to be, but I don't know how else to put it.
The whole setState inside your method is the problem. Your method should do one thing: get a date and time from the user. And there it's responsibility ends.
Future<DateTime> SelectDayAndTimeL(BuildContext context) async {
DateTime _selectedDay = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2021),
lastDate: DateTime(2030),
builder: (BuildContext context, Widget child) => child);
TimeOfDay _selectedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (_selectedDay != null && _selectedTime != null) {
//a little check
}
return DateTime(
_selectedDay.year,
_selectedDay.month,
_selectedDay.day,
_selectedTime.hour,
_selectedTime.minute,
);
}
Now your onPressed becomes:
onPressed: () async {
final pickedDatetime = await SelectDayAndTimeL(context);
setState(() { selectedDateAndTime = pickedDatetime });
},
You have sucessfully divided your code into the function that picks a thing and your widget, which updates after the thing is picked.
The function that picks the date and time can now be reused in every other widget.
Create a function which will take datetime as a parameter and setstate of the stateful widget. Write this inside the stateful widget. Pass this function to the other class as an argument. Once the date is picked call this method by passing the datetime selected.
You should pass the setState function itself as a parameter to the method. This way, inside the method you will always be using the correct state setter function. That is especially necessary since you need to keep the variables _selectedDay etc inside the widget, not on the static method. Try this:
Future selectDayAndTimeL(BuildContext context, Function(DateTime) dateTimeSetter) async { //add a function to receive and use the
DateTime _selectedDay = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2021),
lastDate: DateTime(2030),
builder: (BuildContext context, Widget child) => child);
TimeOfDay _selectedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (_selectedDay != null && _selectedTime != null) {
//a little check
}
// Create the variable with the picked date
DateTime selectedDateAndTime = DateTime(
_selectedDay.year,
_selectedDay.month,
_selectedDay.day,
_selectedTime.hour,
_selectedTime.minute,
);
//call the function from the parameter, which will be executed on the calling widget
dateTimeSetter(selectedDateAndTime);
....
}
Then, call your function to show the datetime picker passing the context, and a function that receives a DateTime parameter, which will be the parameter picked by the user. When the user picks a date, this function body will be executed, calling setState and setting the pickedTime variable.
class Picker extends StatefulWidget {
DateTime pickedTime;
#override
_PickerState createState() => _PickerState();
}
class _PickerState extends State<Picker> {
#override
Future<Widget> build(BuildContext context) async {
return ...
_selectDayAndTimeL(context, (DateTime time){
setState((){
widget.pickedTime = time;
});
});
...
You can also extract the function from the parameter into a normal named function, and just use its name in the parameter, but I'll leave it as is for now to make it simpler.
Also, don't forget to make your method public and static if necessary for the scope of your code.
I created a showTimePicker and I changed the format in 24h, but when I am extracting the value in the ".then" future I get the time in 12h format. Can somebody tell me where is the issue? This is the code:
void _presentTimePicker() {
showTimePicker(
context: context,
initialTime: TimeOfDay(
hour: TimeOfDay.now().hour,
minute: (TimeOfDay.now().minute - TimeOfDay.now().minute % 10 + 10)
.toInt()),
builder: (BuildContext context, Widget child) {
return MediaQuery(
data:
MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),
child: child);
}).then((value) {
if (value == null) return;
setState(() {
time.text = TimeOfDay(
hour: value.hour,
minute: value.minute,
).format(context);
print(time.text);
});
});
}
the output is: 5:50 PM when I selected in picker 17:50
This issue is how you are changing the time of day back to a string. Try using this instead, so that you can override the default.
localizations.formatTimeOfDay(TimeOfDay(
hour: value.hour,
minute: value.minute,
), alwaysUse24HourFormat: true);
(The default is derived from MediaQuery - see here for more details of how.)
I have a basic AR app with Fluttern, using the arcore_flutter_plugin plugin, which I made following some tutorials. I am trying to do some actions when the arCoreController.onNodeTap and onPlaneTap are triggered. But it doesn't seem to work. The code shows no errors, but nothing happens when I tap the node or the plane.
void _onArCoreViewCreated(ArCoreController controller) {
arCoreController = controller;
arCoreController.onPlaneTap = _onPlaneTap;
arCoreController.onNodeTap= handleTap;
}
_onPlaneTap(List<ArCoreHitTestResult> hits) => _onHitDetected(hits.first);
void handleTap(String name){
print('Node Tapped');
showDialog<void>(
context: context,
builder: (BuildContext context) =>
AlertDialog(content: Text('onNodeTap on $name')),
);
}
void _onHitDetected(ArCoreHitTestResult plane){
showDialog<void>(
context: context,
builder: (BuildContext context) =>
AlertDialog(content: Text('On Plane Tap done')),
);
}
What can be the problem?
You need to set enableTapRecognizer to true.
For example:
body: ArCoreView(
enableTapRecognizer: true,
onArCoreViewCreated: _onArCoreViewCreated,
)
i'm currently working on a app which basically works like a database. I want it to fetch data from my sqflite database and use it as text. For some reason I only get "Index of Object" instead of the correct value as text. This is my code in database_helper.dart:
Future<Obj> getName(int id) async {
final db = await database;
var res = await db.query(table, columns: [objName], where: "objId= ?", whereArgs: [id]);
await print(res); //returns right value
return await res.isNotEmpty ? Fish.fromMap(res.first) : Null ;
}
}
and this is my FutureBuilder
FutureBuilder(
future: dbHelper.getName(1),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListTile(
leading: Icon(Icons.message),
title: Text('${snapshot.data}'),
subtitle: Text(""),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NextPage()),
);
}
);
}
return Container();
},
),
I feel like I tried everything. Printing res directly from database_helper.dart gives the right result.
I'd love some tipps! Thanks in advance!
FutureBuilder is working fine and is returning data.You have one Fish object returned from your getName future.
snapshot.data has returned one Fish object.To show any property you can use snapshot.data.propertyName of Fish Model.
I am using a package called Just Audio in my Flutter app. It provides an playBackEvent: playbackEvent.currentPosition which shows the time position that has been played in the Audio file. However I'm a little new to Dart and don't really understand how to subscribe a listener to this event so that I can do something with the changing values.
What I want to do is run a function which sets state when the value changes so I can show the progress and let the users know how far through the Audio file they are at that moment.
Can someone please explain to me how I should do this?
Any help would be much appreciated.
A complete sample available here.
StreamBuilder<Duration>(
stream: _player.durationStream,
builder: (context, snapshot) {
final duration = snapshot.data ?? Duration.zero;
return StreamBuilder<Duration>(
stream: _player.getPositionStream(),
builder: (context, snapshot) {
var position = snapshot.data ?? Duration.zero;
if (position > duration) {
position = duration;
}
return SeekBar(
duration: duration,
position: position,
onChangeEnd: (newPosition) {
_player.seek(newPosition);
},
);
},
);
},
),