[英]How to call a function in a Stateful Widget from another StatefulWidget?
[英]How to call Void() function in another Stateful widget
我想在另一个有状态小部件中调用 void play() 方法
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我想在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**
),
已经调用了starRecording和stopRecording
当 onPressed 时所有三个功能都不起作用,它们是 startRecording、stopRecording 和 play。 这些 function 在 main.dart 中工作正常,但在 voiceCreate.dart 中没有
Dart 函数是一流的,这意味着您可以像变量一样传递它们。 在您的小部件 class 上有一个VoidCallback
成员。
MyHomePage(this.playCallback, {Key key, this.title}) : super(key: key);
final String title;
final VoidCallback playCallback;
您可以在构造函数中传递它。
child: MyHomePage(play)
然后你可以在你的 state object 中找到它。
class _MyHomePageState extends State<MyHomePage> {
...
onPressed: widget.playCallback
...
}
警告
这不是实现此目的的推荐方法。 如果可能,小部件必须包含零业务逻辑。 像这个答案这样的小技巧会让你的代码变得非常复杂。 考虑阅读state 管理解决方案。
答案 3.0
根据您显示的完整代码,这里是仅根据您的代码的解决方案。 我相信它会为你消除一些困惑。
play()
从您的FloatingActionButton
中的main.dart
正确传递到您的MyHomePage
。 我没有使用main.dart
的完整代码,但特别是您要移至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);
}),
);
}
MyHomePage
构造函数中传递。 这将保持原样。 只需查看此处代码的最后一行,看看我们如何使用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();
}
现在如何在您的 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
)
注意:请同时查看我代码中的注释
现在检查这是否适合您。 这应该可以解决您的问题。
我认为其他 2 个让您大致了解如何按照您想要的方式进行操作。 使用这些方法没有任何问题。 它们将起作用,除非当导航开始变得有点复杂时,您将开始使用更多页面并且您可能需要继续将其传递到树中。
所以像easeccy提到的更多地关注state管理。 Blocs , Redux 之类的东西都非常有帮助。 原因就像 flutter 如何根据 setstate() 构建事物一样,state 管理类允许您在不同的地方添加相同的事件,只要它们属于相同的实例。 所有的建筑商都将根据他们生产的 state 进行重建。
例如,对于 Blocs,如果您要向 bloc 添加一个 play 事件。 无论您身在何处,只要您能够向页面提供块,您就可以添加事件和屏幕上的任何内容(如果您要构建多个 dart 文件)都将根据您的 state 进行重建会产生。
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(),
)
}
您拥有的任何其他小部件/构建
@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.