简体   繁体   English

如何在另一个有状态小部件中调用 Void() function

[英]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已经调用了starRecordingstopRecording

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.我相信它会为你消除一些困惑。

  • Passing the 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);
                }),
              );
            }
  • Secondly, use your method to be passed in your 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.

相关问题 如何从另一个有状态小部件调用有状态小部件中的函数? - How to call a function in a Stateful Widget from another StatefulWidget? 如何在另一个有状态小部件中调用方法 - How to call a method in another stateful widget 如何在具有来自另一个有状态小部件的 setState function 的 class 中调用 function ? - How can I call a function in a class that has the setState function from another stateful widget? Flutter,如何从返回的 Widget 调用 Stateful Widget 内部的函数? - Flutter, how to call a function inside Stateful Widget from a returned Widget? 从另一个StatefulWidget的Stateful Widget调用函数 - Call function from Stateful Widget from another StatefulWidget 从 Flutter 中的另一个 dart 文件在有状态小部件 class 下使用 SetState 方法调用 void - Call void with SetState method under stateful widget class from another dart file in Flutter 从另一个有状态小部件调用一个有状态小部件中的方法 - Flutter - call method in one stateful widget from another stateful widget - Flutter 如何在 function 外部的有状态小部件内部调用 flutter function? - how to call flutter function that is inside stateful widget in outside function? 如何在来自另一个 class 的有状态小部件中触发 function(当 onUnityAdsFinish 时)? - How to trigger a function in a stateful widget from another class (when onUnityAdsFinish)? 如何将 void 函数从同一个小部件传递给另一个小部件,然后将相同的 void 函数从另一个小部件返回到同一个小部件中颤振 - how to pass the void function from same widget to another widget and then return the same void function from another widget to same widget in flutter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM