我想在另一个有状态的小部件中调用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。这些功能在main.dart中可以正常运行,但在voiceCreate.dart中则无法运行
答案 0 :(得分:0)
Dart函数是一流的,这意味着您可以像传递变量一样传递它们。在您的小部件类上有一个VoidCallback
成员。
MyHomePage(this.playCallback, {Key key, this.title}) : super(key: key);
final String title;
final VoidCallback playCallback;
您可以在构造函数中传递它。
child: MyHomePage(play)
然后您可以在状态对象中到达它。
class _MyHomePageState extends State<MyHomePage> {
...
onPressed: widget.playCallback
...
}
警告
这不是推荐的方法。窗口小部件必须尽可能包含零业务逻辑。像这样的答案,会使您的代码变得非常复杂。考虑阅读state management解决方案。
答案 1 :(得分:0)
答案3.0
根据您显示的完整代码,这里仅是根据您的代码提供的解决方案。我相信它将为您清除一些困惑。
play()
从MyHomePage
中的main.dart
正确地传递到FloatingActionButton
。我没有使用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
构造函数中传递。这将保持不变。只需看一下代码的最后一行,看看我们如何使用您的play()
传递的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();
}
现在如何在您的班级中使用它
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 :(得分:0)
我认为其他2种方法可以使您大致了解所需的方式。 使用这些方法没有错。它们将起作用,除非导航开始变得有点复杂,您将开始使用更多页面,并且可能需要不断将其传递到树上。
因此,像easyccy提到的那样,更多地关注状态管理。 Blocs,Redux之类的东西都非常有帮助。 就像flutter如何根据setstate()构造事物的原因一样,状态管理类允许您在不同的位置添加相同的事件,只要它们属于同一实例即可。所有建设者将根据其产生的状态进行重建。
例如如果您要向团体添加播放事件,则为Blocs。无论您身在何处,只要能够在页面上提供集团,您都可以添加事件,并且屏幕上的所有内容(如果要构建多个dart文件)都将根据您的状态进行重新构建将产生。
集团的例子 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.
}
),
);
}