How to use FormState in Form's parent widget? - flutter

To validate the whole Form in flutter, a GloabalKey<FormState> must be provided. It looks fine when buttons for interaction with the form contained inside of form, but when, for example, form is a child of AlertDialog, the key has to be passed from the dialog widget, and it doesn't look good. Is there any better solution for obtaining FormState from a parent widget?
Here's the example:
main
void main() {
runApp(
const MaterialApp(
home: InitialScreen(),
),
);
}
Initial Screen
class InitialScreen extends StatelessWidget {
const InitialScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
showDialog<void>(
context: context,
builder: (BuildContext context) {
return FormDialog();
},
);
},
),
);
}
}
Form Dialog
class FormDialog extends StatelessWidget {
FormDialog({super.key});
GlobalKey<FormState> myFormState = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Create new item'),
content: MyForm(
formCurrentState: myFormState,
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Add'),
onPressed: () {
if (myFormState.currentState!.validate()) {
print("All fine");
Navigator.of(context).pop();
} else {
print("Error");
}
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
}
}
My Form
class MyForm extends StatefulWidget {
const MyForm({super.key, required this.formCurrentState});
final GlobalKey<FormState> formCurrentState;
#override
State<MyForm> createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
GlobalKey<FormState>? formCurrentState;
#override
void initState() {
super.initState();
formCurrentState = widget.formCurrentState;
}
#override
Widget build(BuildContext context) {
return Form(
key: formCurrentState,
child: TextFormField(
validator: (value) {
if (value == "") {
return "Please, enter some text";
} else {
return null;
}
},
),
);
}
}

I think there is no better solution to get FormState from parent widget.
If you don't want to make another widget (MyForm), try this code:
class FormDialog extends StatelessWidget {
FormDialog({super.key});
GlobalKey<FormState> myFormState = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Create new item'),
content: Form(
key: formCurrentState,
child: TextFormField(
validator: (value) {
if (value == "") {
return "Please, enter some text";
} else {
return null;
}
},
),
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Add'),
onPressed: () {
if (myFormState.currentState!.validate()) {
print("All fine");
Navigator.of(context).pop();
} else {
print("Error");
}
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
}
}

Related

Call Function From Another Flutter Class

I would like to call function between another clas. So when the menu tapped from grabDrawer it will change the currentIndex at Main() class. Do you know how to do that? Here is so far I have tried.
main.dart
class _MainState extends State<Main> {
int currentIndex = 0;
Map<String,dynamic> searchParameter = {};
List screens = [
Home(),
Search({}),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
actions: [
Builder(builder: (context){
return IconButton(
onPressed: (){
Scaffold.of(context).openEndDrawer();
},
icon: const Icon(Icons.menu),
);
}),
],
),
endDrawer: const Drawer(
child:DrawerObject(),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.arrow_upward),
onPressed: () async{
await Future.delayed(Duration(milliseconds: 100),(){
globals.scrollController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
});
},
),
body: screens[currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
onTap: (index) => setState(() {
if (index == 1) {
getSearchForm(context);
} else {
currentIndex = index;
searchParameter = {};
}
}),
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey[100],
type: BottomNavigationBarType.shifting,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.blue[500],
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Pencarian',
backgroundColor: Colors.orange[500],
),
],
),
);
}
//main function ===> NEED TO CALL THIS FUNCTION INSIDE grabDrawer.dart
Future UpdateIndex({int Index = 0}) async{
setState(() {
currentIndex = Index;
});
}
Future getSearchForm(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SearchForm(parameter:searchParameter)),
);
setState(() {
if (result != null) {
currentIndex = 1;
if(result!=searchParameter){
searchParameter = result;
screens[1] = CallLoading(show: ''); //set default to load
//set to new parameter (rebuilding widget)
Future.delayed(Duration(milliseconds: 500),(){
setState(() {
screens[1] = Search(searchParameter);
});
});
}
}
else{
}
});
}
}
Under this file, I need to call function from Main.UpdateIndex.
grabDrawer.dart
class DrawerObject extends StatelessWidget {
const DrawerObject({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.home),
title: Text('Cari Properti?'),
onTap: (){
===> CALL IT HERE
}
),
],
),
);
}
}
I really appreciate any answers. Thank you.
Change your grabDrawer.dart like this
class DrawerObject extends StatelessWidget {
void Function()? UpdateIndex;
DrawerObject({
this.UpdateIndex,
});
#override
Widget build(BuildContext context) {
return Container(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.home),
title: Text('Cari Properti?'),
onTap: (){
UpdateIndex!();
}
),
],
),
);
}
}
And in your main.dart, call Drawer class like this
endDrawer: const Drawer(
child:DrawerObject(
UpdateIndex: UpdateIndex,
);
),
Hope this works for you.
Here is the clear way to pass data between one class to another class
void main() {
runApp(MaterialApp(
home: Modalbtn(),
));
}
class Modalbtn extends StatefulWidget {
#override
_ModalbtnState createState() => _ModalbtnState();
}
class _ModalbtnState extends State<Modalbtn> {
String value = "0";
// Pass this method to the child page.
void _update(String newValue) {
setState(() => value = newValue);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: [StatefulModalbtn(update: _update)],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
),
Text(
value,
style: TextStyle(fontSize: 40),
),
],
),
),
);
}
}
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatelessWidget {
final ValueChanged<String> update;
StatefulModalbtn({required this.update});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => update("100"), // Passing value to the parent widget.
child: Text('Update (in child)'),
);
}
}

How do I activate button if at least one checkbox is selected? - Flutter

I have an alert dialog that displays a series of check boxes.
I am trying to ensure that if at least one of the checkboxes is selected, the confirm button is enabled, otherwise, if no checkbox is selected, it appears as inactive.
I have a parent and a child widget, both statefull. In one of them I have the button that should be enabled / disabled, and in the other one I have the content of the alert dialog.
The challenge for me has been to notify the parent widget from the child widget, that the flag variable with which I determine whether the button should be active or not, has been updated.
I have tried sending a function to the child widget that it executes, also with ValueSetter and ValueChanged, but so far without success.
If after activating or inactivating one of the checkboxes, I do a hot reload, the button is also updated. So I think it may be something with setState that I am not taking into account.
This is what I have done so far, ready to copy and paste into dartPad.
Thanks for your help.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: FrequencySelectionPage(),
),
),
);
}
}
class FrequencySelectionPage extends StatefulWidget {
FrequencySelectionPage();
#override
_FrequencySelectionPageState createState() => _FrequencySelectionPageState();
}
class _FrequencySelectionPageState extends State<FrequencySelectionPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListTile(
leading: Icon(Icons.calendar_today),
title: Text('Some days of the week'),
trailing: Icon(Icons.keyboard_arrow_right_rounded),
onTap: () {
_showDialog(context);
}
),),
);
}
void _showDialog(BuildContext context) {
final double screenSize = MediaQuery.of(context).size.height;
bool? canConfirm;
void setCanConfirm(bool value) {
setState(() {
canConfirm = value;
});
}
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Choose days"),
content: Container(
width: 200,
height: screenSize * 0.60,
child: ShowAlertContent(
setCanConfirm: setCanConfirm),
),
actions: <Widget>[
SizedBox(
width: screenSize * 0.50,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
SizedBox(
height: 20.0,
width: 20.0,
),
ElevatedButton(
child: Text('Confirm'),
onPressed: (canConfirm == false)
? null
: () {
Navigator.of(context).pop();
},
),
],
),
)
],
);
},
);
}
}
class ShowAlertContent extends StatelessWidget {
final ValueSetter<bool> setCanConfirm;
const ShowAlertContent(
{required this.setCanConfirm});
#override
Widget build(BuildContext context) {
return ShowSomeWeekDaysOptionContent(setCanConfirm: setCanConfirm);
}
}
class ShowSomeWeekDaysOptionContent extends StatefulWidget {
final ValueChanged<bool> setCanConfirm;
const ShowSomeWeekDaysOptionContent({required this.setCanConfirm});
#override
_ShowSomeWeekDaysOptionContentState createState() =>
_ShowSomeWeekDaysOptionContentState();
}
class _ShowSomeWeekDaysOptionContentState
extends State<ShowSomeWeekDaysOptionContent> {
Map<String, bool> days = {
'Day1': false,
'Day2': false,
'Day3': false,
'Day4': false,
'Day5': false,
'Day6': false,
'Day7': false
};
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ListView(
padding: EdgeInsets.all(8.0),
children: days.keys.map(
(day) {
return StatefulBuilder(builder:
(BuildContext context, StateSetter setCheckboxState) {
return CheckboxListTile(
title: Text(day),
value: days[day],
onChanged: (bool? value) {
setState(() {});
setCheckboxState(() {
days[day] = value!;
if (days.containsValue(true)) {
widget.setCanConfirm(true);
} else {
widget.setCanConfirm(false);
}
});
},
);
});
},
).toList(),
),
),
],
);
}
}
In your example you need something which rebuilds the button, when the value of canConfirm changes. You could use a ValueListenableBuilder. Therefore you have to make canConfirm a ValueNotifier.
Here is the working example:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: FrequencySelectionPage(),
),
),
);
}
}
class FrequencySelectionPage extends StatefulWidget {
FrequencySelectionPage();
#override
_FrequencySelectionPageState createState() => _FrequencySelectionPageState();
}
class _FrequencySelectionPageState extends State<FrequencySelectionPage> {
late ValueNotifier<bool> canConfirm;
#override
void initState() {
canConfirm = ValueNotifier(false);
super.initState();
}
void setCanConfirm(bool value) {
canConfirm.value = value;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListTile(
leading: Icon(Icons.calendar_today),
title: Text('Some days of the week'),
trailing: Icon(Icons.keyboard_arrow_right_rounded),
onTap: () {
_showDialog(context);
}),
),
);
}
void _showDialog(BuildContext context) {
final double screenSize = MediaQuery.of(context).size.height;
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Choose days"),
content: Container(
width: 200,
height: screenSize * 0.60,
child: ShowAlertContent(setCanConfirm: setCanConfirm),
),
actions: <Widget>[
SizedBox(
width: screenSize * 0.50,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
SizedBox(
height: 20.0,
width: 20.0,
),
ValueListenableBuilder<bool>(
valueListenable: canConfirm,
builder: (context, value, child) {
return ElevatedButton(
child: Text('Confirm'),
onPressed: (value == false)
? null
: () {
Navigator.of(context).pop();
},
);
},
),
],
),
)
],
);
},
);
}
}
class ShowAlertContent extends StatelessWidget {
final ValueSetter<bool> setCanConfirm;
const ShowAlertContent({required this.setCanConfirm});
#override
Widget build(BuildContext context) {
return ShowSomeWeekDaysOptionContent(setCanConfirm: setCanConfirm);
}
}
class ShowSomeWeekDaysOptionContent extends StatefulWidget {
final ValueChanged<bool> setCanConfirm;
const ShowSomeWeekDaysOptionContent({required this.setCanConfirm});
#override
_ShowSomeWeekDaysOptionContentState createState() =>
_ShowSomeWeekDaysOptionContentState();
}
class _ShowSomeWeekDaysOptionContentState
extends State<ShowSomeWeekDaysOptionContent> {
Map<String, bool> days = {
'Day1': false,
'Day2': false,
'Day3': false,
'Day4': false,
'Day5': false,
'Day6': false,
'Day7': false
};
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ListView(
padding: EdgeInsets.all(8.0),
children: days.keys.map(
(day) {
return StatefulBuilder(builder:
(BuildContext context, StateSetter setCheckboxState) {
return CheckboxListTile(
title: Text(day),
value: days[day],
onChanged: (bool? value) {
setCheckboxState(() {
days[day] = value!;
if (days.containsValue(true)) {
widget.setCanConfirm(true);
} else {
widget.setCanConfirm(false);
}
});
},
);
});
},
).toList(),
),
),
],
);
}
}
I don’t know about your case but ummmm.. I think this one maybe a lot easier
`bool _isChecked = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Checkbox(
value: _isChecked,
onChanged: (value) {
setState(() {
_isChecked = value;
});
},
),
ElevatedButton(
child: Text('Button'),
onPressed: (){
if(_isChecked){
print('CHeckbox is checked');
}else{
print('CHeckbox is not checked');
}
},
),
],
);
}`

Dart- Exception after run my flutter search app

My question about how can i handle this exception error that appear on my mobile when i execute it with red screen
i'm new with flutter and I have wrote simple search bar widget. After executing it got exception:
ErrorSummary('MediaQuery.of() called with a context that does not contain a MediaQuery.'),
ErrorDescription(
'No MediaQuery ancestor could be found starting from the context that was passed '
'to MediaQuery.of(). This can happen because you do not have a WidgetsApp or '
'MaterialApp widget (those widgets introduce a MediaQuery), or it can happen '
'if the context you use comes from a widget above those widgets.'
This is main.dart for searchbar:
import 'package:flutter/material.dart';
void main() {
runApp(MyFirstApp());
}
class MyFirstApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Search..."),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch());
})
],
),
drawer: Drawer(),
);
}
}
class DataSearch extends SearchDelegate<String> {
final data1 = ["Amr", "Amir", "Moatasem", "Gamal", "Tasneem"];
final data2 = ["Amr", "Amir"];
#override
List<Widget> buildActions(BuildContext context) {
return <Widget>[
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = " ";
})
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {
return Container(
child: Center(
child: Text(query),
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestion = query.isEmpty
? data2
: data1.where((p) => p.startsWith(query)).toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context);
},
leading: Icon(Icons.question_answer),
title: RichText(
text: TextSpan(
text: suggestion[index].substring(0, query.length),
style:
TextStyle(color: Colors.black, fontStyle: FontStyle.italic),
children: [
TextSpan(
text: suggestion[index].substring(query.length),
style: TextStyle(color: Colors.red))
]),
),
),
itemCount: suggestion.length,
);
}
}
This is Widget test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testtest/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyFirstApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
I have found MediaQuery.of but don't understand how can it be used with existing widget? It accept BuildContext as parameter.
static MediaQueryData of(BuildContext context, { bool nullOk = false }) {
assert(context != null);
assert(nullOk != null);
final MediaQuery query = context.dependOnInheritedWidgetOfExactType<MediaQuery>();
if (query != null)
return query.data;
Your application lacks a MaterialApp Widget which is a required at top level. That's causing this error .
The bellow code will solve this issue:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyFirstApp(),
);
}
}
class MyFirstApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Search..."),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch());
})
],
),
drawer: Drawer(),
);
}
}
class DataSearch extends SearchDelegate<String> {
final data1 = ["Amr", "Amir", "Moatasem", "Gamal", "Tasneem"];
final data2 = ["Amr", "Amir"];
#override
List<Widget> buildActions(BuildContext context) {
return <Widget>[
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = " ";
})
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {
return Container(
child: Center(
child: Text(query),
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestion = query.isEmpty
? data2
: data1.where((p) => p.startsWith(query)).toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context);
},
leading: Icon(Icons.question_answer),
title: RichText(
text: TextSpan(
text: suggestion[index].substring(0, query.length),
style:
TextStyle(color: Colors.black, fontStyle: FontStyle.italic),
children: [
TextSpan(
text: suggestion[index].substring(query.length),
style: TextStyle(color: Colors.red))
]),
),
),
itemCount: suggestion.length,
);
}
}

How to call child method from parent for another widget

main.dart
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:permission_handler/permission_handler.dart';
import 'regitration.dart';
//import 'voiceCreate.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String statusText = "";
bool isComplete = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
drawer: Drawer(
elevation: 2.0,
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MyApp();
},
),
);
},
),
ListTile(
title: Text('Sign up'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
title: Text('Myvo'),
centerTitle: true,
backgroundColor: Colors.tealAccent.shade700,
),
body: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 40,
onPressed: () async {
startRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.pause),
color: Colors.white,
iconSize: 40,
onPressed: () async {
pauseRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 40,
onPressed: () async {
stopRecord();
}),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
statusText,
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
play();
},
child: Container(
margin: EdgeInsets.only(top: 30),
alignment: AlignmentDirectional.center,
width: 100,
height: 50,
child: isComplete && recordFilePath != null
? Text(
"play",
style: TextStyle(color: Colors.red, fontSize: 20),
)
: Container(),
),
),
]),
),
),
);
}
Future<bool> checkPermission() async {
if (!await Permission.microphone.isGranted) {
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
return false;
}
}
return true;
}
void startRecord() async {
bool hasPermission = await checkPermission();
if (hasPermission) {
statusText = "Recording...";
recordFilePath = await getFilePath();
isComplete = false;
RecordMp3.instance.start(recordFilePath, (type) {
statusText = "Record error--->$type";
setState(() {});
});
} else {
statusText = "No microphone permission";
}
setState(() {});
}
void pauseRecord() {
if (RecordMp3.instance.status == RecordStatus.PAUSE) {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
} else {
bool s = RecordMp3.instance.pause();
if (s) {
statusText = "Recording pause...";
setState(() {});
}
}
}
void stopRecord() {
bool s = RecordMp3.instance.stop();
if (s) {
statusText = "Record complete";
isComplete = true;
setState(() {});
}
}
void resumeRecord() {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
}
String recordFilePath;
void play() {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
AudioPlayer audioPlayer = AudioPlayer();
audioPlayer.play(recordFilePath, isLocal: true);
}
}
int i = 0;
Future<String> getFilePath() async {
Directory storageDirectory = await getApplicationDocumentsDirectory();
String sdPath = storageDirectory.path + "/record";
var d = Directory(sdPath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
return sdPath + "/test_${i++}.mp3";
}
}
I want to call the VoiceCreate function when clicking on onPressed
voiceCreate.dart
import 'package:flutter/material.dart';
import 'main.dart';
class VoiceCreate extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () {}),
),
),
);
}
}
I want to call startRecord method from main.dart when clicking on onPressed
If you check the code of IconButton you'll see that onPressed is a VoidCallback, you can try to imitate the logic to do the same
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
And in main just call your widget VoiceCreate with an onPressed parameter
VoiceCreate(
onPressed: () => startRecord
)
edited code here. Still the startRecord() is not working. VoiceCreate() is working
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return VoiceCreate(onPressed: startRecord);
}),
);
},
// Add your onPressed code here!
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
You could do this by using shared view model across need widgets, like so:
I'd recommend to use this approach instead of callbacks and Stateful widgets
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Parent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<CommonViewModel>(
init: CommonViewModel(),
builder: (model) {
return Scaffold(
body: Column(
children: [
RaisedButton(onPressed: () => model.parentMethod(0)),
RaisedButton(onPressed: () => model.childMethod('call from parent')),
],
),
);
},
);
}
}
class Child extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<CommonViewModel>(
builder: (model) {
return Scaffold(
body: Column(
children: [
RaisedButton(onPressed: () => model.childMethod('call from child')),
RaisedButton(onPressed: () => model.parentMethod(100)),
],
),
);
},
);
}
}
class CommonViewModel extends GetxController {
void parentMethod(int argument) {
print('Parent method $argument');
}
void childMethod(String argument) {
print('Child method $argument');
}
}

flutter: Another exception was thrown: No MaterialLocalizations found

I am trying to show an Alert Dialog on press of a button in Flutter.
Following is my code
main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Different Widgets",
debugShowCheckedModeBanner: false,
home: showAlertDialog()
);
}
void _dialogResult(String value) {
if (value == "YES") {
print("YES");
} else {
print("NO");
}
Navigator.pop(context);
}
Widget showAlertDialog() {
TextEditingController textEditingController = TextEditingController();
return Scaffold(
appBar: AppBar(
title: Text("Different Widgets"),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
TextField(
controller: textEditingController,
),
RaisedButton(
onPressed: () {
print("Hi");
AlertDialog dialog = AlertDialog(
title: Text("Hi"),
content: Text(
textEditingController.text,
style: TextStyle(fontSize: 30.0),
),
actions: <Widget>[
FlatButton(
onPressed: () {
_dialogResult("YES");
},
child: Text("YES")),
FlatButton(
onPressed: () {
_dialogResult("NO");
},
child: Text("NO")),
],
);
showDialog(context: context, builder: (BuildContext context) => dialog);
},
child: Text("Click Me"),
)
],
),
),
),
);
}
What does this has to do with Localisation, I cannot follow. I did the same steps as per the docs. I am able to see the button but on click of that button I keep getting error. I tried writing print statement inside of button click and the print statement appears in the log, definitely something wrong with AlertDialog.
You may get No MaterialLocalizations found error while showing dialog using showDialog() class in Flutter. The issue is putting child widget on home property of MaterialApp() widget without creating new widget class.
One way to solve is putting MaterialApp() inside runApp() and create new class for home property.
import 'package:flutter/material.dart';
main() {
runApp(
MaterialApp(
home: MyApp(),
title: "Different Widgets",
debugShowCheckedModeBanner: false,
),
);
}
/*
place MaterialApp() widget on runApp() and create
new class for its 'home' property
to escape 'No MaterialLocalizations found' error
*/
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return showAlertDialog();
}
void _dialogResult(String value) {
if (value == "YES") {
print("YES");
} else {
print("NO");
}
Navigator.pop(context);
}
Widget showAlertDialog() {
TextEditingController textEditingController = TextEditingController();
return Scaffold(
appBar: AppBar(
title: Text("Different Widgets"),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
TextField(
controller: textEditingController,
),
RaisedButton(
onPressed: () {
print("Hi");
AlertDialog dialog = AlertDialog(
title: Text("Hi"),
content: Text(
textEditingController.text,
style: TextStyle(fontSize: 30.0),
),
actions: <Widget>[
FlatButton(
onPressed: () {
_dialogResult("YES");
},
child: Text("YES")),
FlatButton(
onPressed: () {
_dialogResult("NO");
},
child: Text("NO")),
],
);
showDialog(
context: context,
builder: (BuildContext context) => dialog);
},
child: Text("Click Me"),
)
],
),
),
),
);
}
}