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');
}
}
Related
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)'),
);
}
}
in flutter,I'm currently working on a feature to edit lists.
I want to be able to display the last text I wrote and add text to it.
But I get an error like the one below.
I don't know how to do this anymore, so I would appreciate any advice on how to write it.
I'm sorry, but I don't understand English, and there are a few places where it's written in Japanese. answers don't have to be in Japanese.
This is my first question.
enter code here
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() {
// 最初に表示するWidget
runApp(Myenter code hereApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// 右上に表示される"debug"ラベルを消す
debugShowCheckedModeBanner: false,
// アプリ名
title: 'My Todo App',
theme: ThemeData(
// テーマカラー
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
// リスト一覧画面を表示
home: TodoListPage(),
);
}
}
// リスト一覧画面用Widget
class TodoListPage extends StatefulWidget {
#override
_TodoListPageState createState() => _TodoListPageState();
}
class _TodoListPageState extends State<TodoListPage> {
// Todoリストのデータ
List<String> todoList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
// AppBarを表示し、タイトルも設定
appBar: AppBar(
title: Text('リスト一覧'),
),
// データを元にListViewを作成
body: ListView.builder(
itemCount: todoList.length,
itemBuilder: (context, index) {
return CupertinoContextMenu(
child: Card(
child: ListTile(
title: Text(todoList[index]),
),
),
actions: <Widget>[
CupertinoContextMenuAction(
child: const Text('Delete'),
//押されたら...
onPressed: () {
setState(() {});
//listの一つを削除
todoList.removeAt(index);
//そして、popで前の画面に戻る
Navigator.pop(context);
},
),
CupertinoContextMenuAction(
child: const Text('To edit'),
onPressed: () async {
var morenewText = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TodoAddPage(todoList[index]),
),
);
setState(() {
todoList[index] = morenewText;
});
},
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// "push"で新規画面に遷移
// リスト追加画面から渡される値を受け取る
var newListText = await Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
// 遷移先の画面としてリスト追加画面を指定
return TodoAddPage(null);
}),
);
if (newListText != null) {
// キャンセルした場合は newListText が null となるので注意
setState(() {
// リスト追加
todoList.add(newListText);
});
}
},
child: Icon(Icons.add),
),
);
}
}
class TodoAddPage extends StatefulWidget {
dynamic oldnama;
TodoAddPage(this.oldnama);
#override
_TodoAddPageState createState() => _TodoAddPageState();
}
class _TodoAddPageState extends State<TodoAddPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('リスト追加'),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 入力されたテキストを表示
Text(widget.oldnama, style: TextStyle(color: Colors.blue)),
const SizedBox(height: 8),
// テキスト入力
TextField(
// 入力されたテキストの値を受け取る(valueが入力されたテキスト)
onChanged: (String value) {
// データが変更したことを知らせる(画面を更新する)
setState(() {
// データを変更
widget.oldnama = value;
});
},
),
const SizedBox(height: 8),
Container(
// 横幅いっぱいに広げる
width: double.infinity,
// リスト追加ボタン
child: ElevatedButton(
onPressed: () {
// "pop"で前の画面に戻る
// "pop"の引数から前の画面にデータを渡す
Navigator.of(context).pop(widget.oldnama);
},
child: Text('Add list', style: TextStyle(color: Colors.white)),
),
),
const SizedBox(height: 8),
Container(
// 横幅いっぱいに広げる
width: double.infinity,
// キャンセルボタン
child: TextButton(
// ボタンをクリックした時の処理
onPressed: () {
// "pop"で前の画面に戻る
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
),
],
),
),
);
}
}
You cant directly modify the widget entry variables
TextField(
// 入力されたテキストの値を受け取る(valueが入力されたテキスト)
onChanged: (String value) {
// データが変更したことを知らせる(画面を更新する)
setState(() {
// データを変更
widget.oldnama = value;
});
},
),
create another variable in state class like
var textValue = user.name;
use textFormField
TextFormField(
initValue: textValue,
onChanged: (value){
setState( () {
textValue = value;
});
},
)
or something like this, the important thing is that you cant do widget.oldnama = value
You can copy paste run full code below
Reason: null value cause Text widget has excepiton, you can change from
Text(widget.oldnama, style: TextStyle(color: Colors.blue)),
to
widget.oldnama == null
? Text("empty")
: Text("${widget.oldnama}",
style: TextStyle(color: Colors.blue)),
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() {
// 最初に表示するWidget
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// 右上に表示される"debug"ラベルを消す
debugShowCheckedModeBanner: false,
// アプリ名
title: 'My Todo App',
theme: ThemeData(
// テーマカラー
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
// リスト一覧画面を表示
home: TodoListPage(),
);
}
}
// リスト一覧画面用Widget
class TodoListPage extends StatefulWidget {
#override
_TodoListPageState createState() => _TodoListPageState();
}
class _TodoListPageState extends State<TodoListPage> {
// Todoリストのデータ
List<String> todoList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
// AppBarを表示し、タイトルも設定
appBar: AppBar(
title: Text('リスト一覧'),
),
// データを元にListViewを作成
body: ListView.builder(
itemCount: todoList.length,
itemBuilder: (context, index) {
return CupertinoContextMenu(
child: Card(
child: ListTile(
title: Text(todoList[index]),
),
),
actions: <Widget>[
CupertinoContextMenuAction(
child: const Text('Delete'),
//押されたら...
onPressed: () {
setState(() {});
//listの一つを削除
todoList.removeAt(index);
//そして、popで前の画面に戻る
Navigator.pop(context);
},
),
CupertinoContextMenuAction(
child: const Text('To edit'),
onPressed: () async {
var morenewText = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TodoAddPage(todoList[index]),
),
);
setState(() {
todoList[index] = morenewText;
});
},
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// "push"で新規画面に遷移
// リスト追加画面から渡される値を受け取る
var newListText = await Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
// 遷移先の画面としてリスト追加画面を指定
return TodoAddPage(null);
}),
);
if (newListText != null) {
// キャンセルした場合は newListText が null となるので注意
setState(() {
// リスト追加
todoList.add(newListText);
});
}
},
child: Icon(Icons.add),
),
);
}
}
class TodoAddPage extends StatefulWidget {
dynamic oldnama;
TodoAddPage(this.oldnama);
#override
_TodoAddPageState createState() => _TodoAddPageState();
}
class _TodoAddPageState extends State<TodoAddPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('リスト追加'),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 入力されたテキストを表示
widget.oldnama == null
? Text("empty")
: Text("${widget.oldnama}",
style: TextStyle(color: Colors.blue)),
const SizedBox(height: 8),
// テキスト入力
TextField(
// 入力されたテキストの値を受け取る(valueが入力されたテキスト)
onChanged: (String value) {
// データが変更したことを知らせる(画面を更新する)
setState(() {
// データを変更
widget.oldnama = value;
});
},
),
const SizedBox(height: 8),
Container(
// 横幅いっぱいに広げる
width: double.infinity,
// リスト追加ボタン
child: ElevatedButton(
onPressed: () {
// "pop"で前の画面に戻る
// "pop"の引数から前の画面にデータを渡す
Navigator.of(context).pop(widget.oldnama);
},
child: Text('Add list', style: TextStyle(color: Colors.white)),
),
),
const SizedBox(height: 8),
Container(
// 横幅いっぱいに広げる
width: double.infinity,
// キャンセルボタン
child: TextButton(
// ボタンをクリックした時の処理
onPressed: () {
// "pop"で前の画面に戻る
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
),
],
),
),
);
}
}
I have created a simple app using InheritedWidget, just a counter app...
I have just four files:
main.dart.
CommonScreenProvider.dart.
first_screen.dart.
second_screen.dart.
the problem here when I am trying to use the counter function in in the second_screen and go back to the first_screen I can not find any updates till I use the counter but while I use counter in first screen I found the updated value in the second screen without problem, I think there's missing a refresh function or something?
Here's the code implementation...
CommonScreenProvider
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
first_screen
import 'package:flutter/material.dart';
import 'package:statemanagementtest/second_screen.dart';
import 'commom_screen_provider.dart';
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () {
Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
);
}),
),
);
}
}
second_screen
import 'package:flutter/material.dart';
import 'commom_screen_provider.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:statemanagementtest/commom_screen_provider.dart';
import 'package:statemanagementtest/first_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
You can copy paste run full code below
Quick fix is move StatefulBuilder up and await Navigator.of(ctx).push then call setState
code snippet
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
working demo
full code
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
)),
);
});
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
I want to show a text after onPressed function happened, this function is a recording function and wants to show a text 'recording' when the function happening
voiceCreate.dart
import 'package:flutter/material.dart';
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),
),
),
);
}
}
**main.dart**
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.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: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return VoiceCreate(onPressed: startRecord);
}),
);
},
// 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(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
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";
}
}
VoiceCreate function will happen on a new page when clicking on the Floating button in main.dart and recording will happen when click on mic Icon, want show the text 'recording' whine the fuction happening.
First of all, you need to have StatefulWidget to manage changes in state, then you can use two functions startRecording and stopRecording to toggle the isRecording variable. Then based on the value of isRecording you can make changes in the view, e.g., displaying a text. For displaying the text you can use a Visibility widget and set its visible parameter to isRecording.
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 70,
onPressed: () => _stopRecording(),
),
Visibility(
visible: _isRecording,
child: Text(
'recording',
style: TextStyle(
color: Colors.red
),
),
)
],
),
),
),
);
}
}
Maybe a snackbar could be useful here, something like:
class VoiceCreate extends StatefulWidget {
VoiceCreate({Key key, this.title}) : super(key: key);
final String title;
#override
_VoiceCreateState createState() => _VoiceCreateState();
}
class _VoiceCreateState extends State<VoiceCreate> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
var isRecording = false;
void showRecordingMessage(String message, [Color color = Colors.red]) {
_scaffoldKey.currentState.showSnackBar(
new SnackBar(backgroundColor: color, content: new Text(message)));
}
void setRecordingState() {
this.setState(() {
isRecording = true;
});
print("isRecording is set to $isRecording");
showRecordingMessage('Recording now!');
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.blueGrey,
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () {
setRecordingState();
},
),
],
),
),
);
}
}
I want to call the void play() method in another stateful widget
main.dart
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.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';
import 'stopwatch.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 StopWatch();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return MyHomePage();
}),
);
},
// 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(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
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; //maybe**strong text** this need to take
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";
}
}
voiceCreate.dart
I want to call here when onPressed
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
MyHomePage.play()**//getting error here**
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.black,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.black,
iconSize: 70,
onPressed: () => _stopRecording(),
),
IconButton(
icon: Icon(Icons.play_arrow),
color: Colors.black,
onPressed: () => `MyHomePage(title: "My title", play: this.play()),`**// getting error here**
),
already called the starRecording and stopRecording
all three functions are not working when onPressed, these are startRecording, stopRecording and play. these function are working okay in main.dart but not in voiceCreate.dart
Dart functions are first-class, that means you can pass them around like a variable. Have a VoidCallback member on your widget class.
MyHomePage(this.playCallback, {Key key, this.title}) : super(key: key);
final String title;
final VoidCallback playCallback;
You can pass it in the constructor.
child: MyHomePage(play)
Then you can reach it in your state object.
class _MyHomePageState extends State<MyHomePage> {
...
onPressed: widget.playCallback
...
}
Warning
This is not a recommended way to achieve this. Widgets must contain zero business logic if possible. Little hacks like this answer will make your code very complex than it should be. Consider reading state management solutions.
I think the other 2 gave you the rough idea of how to do it the way you want.
There is nothing wrong using those methods. They will work except when the navigation starts to get a little complex you will start using more pages and you might need to keep passing it down the tree.
So like easeccy mention look more into state management.
Things like Blocs, Redux are all very helpful.
Reason being just like how flutter builds things depending on setstate() the state management classes allows you to add the same event at different places as long as they are of the same instance. All the builders will rebuild based off the state they yield.
E.g. for Blocs if you were to add a play event to the bloc. no matter where you are as long as you are able to provide the bloc to the page you can add the event and anything that is on the screen (if you were to have multiple dart files building) will all be rebuilt depending on the state you will yield.
example of bloc
main.dart
void main() async{
runApp(
//Having this before return MaterialApp() ensures that you can call it
//anywhere in the app below this tree
BlocProvider<TheTypeOfBloc>(
create: (context) => TheTypeOfBloc(),
child: App(),
)
}
any other widgets/builds you have
#override
Widget build(BuildContext context) {
return BlocListener<TheTypeOfBloc,TheTypeOfState>(
listener : (context,state){
//tldr of listen = when your state change do something.
//so your void function can be call here
if(state is playState){
_play();
}
}
child:BlocBuilder<TheTypeOfBloc,TheTypeOfState> (
// basically anything below here gets rebuild when you change a state.
builder: (context,state) {
return //what you want to build here like listener based on the
//state or just build normally without the builder.
}
),
);
}
Answer 3.0
As per the full code you have shown, here is the solution as per your code only. I am sure it will clear out some confusions for you.
Passing the play() correctly to your MyHomePage from main.dart in your FloatingActionButton. I am not using full code of main.dart, but specifically your part, where you are moving to the MyHomePage
main.dart
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
// you need to pass two positional arguments
// since your MyHomePage accepts two arguments
// one is your title and one is your function
return MyHomePage(title: "My Title", play: play);
}),
);
}
Secondly, use your method to be passed in your MyHomePage constructor. This will remain as is. Just look at the last line of the code here, and see how are we using the passed play() method from your main.dart
class MyHomePage extends StatefulWidget {
// accepting the method in the constructor
// so you can pass it with the title from your main.dart
MyHomePage({Key key, this.title, this.play}) : super(key: key);
final String title;
final Function play; // this is the function
#override
_MyHomePageState createState() => _MyHomePageState();
}
Now how to use that in your Class
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.black,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.black,
iconSize: 70,
onPressed: () => _stopRecording(),
),
IconButton(
icon: Icon(Icons.play_arrow),
color: Colors.black,
onPressed: () => widget.play() // call like this
)
Note: Please look at the comments in my code as well
Now check if that works for you. This should probably fix your problem.