[英]How to call Void() function in another Stateful widget
I want to call the void play() method in another stateful widget我想在另一个有状态小部件中调用 void play() 方法
main.dart 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
voiceCreate.dart我想在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已经调用了starRecording和stopRecording
all three functions are not working when onPressed, these are startRecording, stopRecording and play.当 onPressed 时所有三个功能都不起作用,它们是 startRecording、stopRecording 和 play。 these function are working okay in main.dart but not in voiceCreate.dart这些 function 在 main.dart 中工作正常,但在 voiceCreate.dart 中没有
Dart functions are first-class, that means you can pass them around like a variable. Dart 函数是一流的,这意味着您可以像变量一样传递它们。 Have a VoidCallback
member on your widget class.在您的小部件 class 上有一个VoidCallback
成员。
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.然后你可以在你的 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.考虑阅读state 管理解决方案。
Answer 3.0答案 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.我相信它会为你消除一些困惑。
play()
correctly to your MyHomePage
from main.dart
in your FloatingActionButton
.将play()
从您的FloatingActionButton
中的main.dart
正确传递到您的MyHomePage
。 I am not using full code of main.dart
, but specifically your part, where you are moving to the MyHomePage
我没有使用main.dart
的完整代码,但特别是您要移至MyHomePage
的部分main.dart 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);
}),
);
}
MyHomePage
constructor.其次,使用您的方法在MyHomePage
构造函数中传递。 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
只需查看此处代码的最后一行,看看我们如何使用main.dart
中传递的play()
方法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 中使用它
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.这应该可以解决您的问题。
I think the other 2 gave you the rough idea of how to do it the way you want.我认为其他 2 个让您大致了解如何按照您想要的方式进行操作。 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.所以像easeccy提到的更多地关注state管理。 Things like Blocs , Redux are all very helpful. Blocs , Redux 之类的东西都非常有帮助。 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.原因就像 flutter 如何根据 setstate() 构建事物一样,state 管理类允许您在不同的地方添加相同的事件,只要它们属于相同的实例。 All the builders will rebuild based off the state they yield.所有的建筑商都将根据他们生产的 state 进行重建。
Eg for Blocs if you were to add a play event to the bloc.例如,对于 Blocs,如果您要向 bloc 添加一个 play 事件。 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.无论您身在何处,只要您能够向页面提供块,您就可以添加事件和屏幕上的任何内容(如果您要构建多个 dart 文件)都将根据您的 state 进行重建会产生。
example of bloc main.dart 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.
}
),
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.