小工具知识网

当前位置: 首页 > 行业知识 > flutter中使用基于flutter

行业知识

flutter中使用基于flutter

2026-11-07 21:13:43 来源:互联网转载

flutter_sound_record

    • 前言
    • 文章案例所使用插件的版本号
    • 插件安装
    • 引入安卓和ios权限
    • 支持的编码
    • 自定义生成的文件名
    • 代码
        • main.dart
        • audio_player.dart
        • 源码地址

          前言

          使用flutter_sound,总是出现莫名的错误,所以改为flutter_sound_record,实现录音录制和播放

          文章案例所使用插件的版本号

          3.3.2

          插件安装

          安装方式:

          命令行形式:

          flutter pub add flutter_sound_record

          pubspec.yaml格式 (别忘运行 pub get):

          dependencies:  flutter_sound_record: ^3.3.2

          引入

          import 'package:flutter_sound_record/flutter_sound_record.dart';

          引入安卓和ios权限

          Android

           

          min SDK: 16 (29 if you use OPUS)

          iOs

          NSMicrophoneUsageDescriptionWe need to access to the microphone to record audio file

          min SDK: 8.0 (11 if you use OPUS)

          支持的编码

          enum AudioEncoder {  /// Will output to MPEG_4 format container  AAC,  /// Will output to MPEG_4 format container  AAC_LD,  /// Will output to MPEG_4 format container  AAC_HE,  /// sampling rate should be set to 8kHz  /// Will output to 3GP format container on Android  AMR_NB,  /// sampling rate should be set to 16kHz  /// Will output to 3GP format container on Android  AMR_WB,  /// Will output to MPEG_4 format container  /// /!\ SDK 29 on Android /!\  /// /!\ SDK 11 on iOs /!\  OPUS,}

          自定义生成的文件名

          在下面main.dart的代码中的 _start() 函数

          await _audioRecorder.start();//path改为自定义的即可,其余参数根据自己需求设置await _audioRecorder.start(  path: 'aFullPath/myFile.m4a', // required  encoder: AudioEncoder.AAC, // by default  bitRate: 128000, // by default  sampleRate: 44100, // by default);

          代码

          main.dart
          import 'dart:async';import 'package:example/audio_player.dart';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:flutter_sound_record/flutter_sound_record.dart';import 'package:just_audio/just_audio.dart' as ap;class AudioRecorder extends StatefulWidget {  const AudioRecorder({required this.onStop, Key? key}) : super(key: key);  final void Function(String path) onStop;  @override  _AudioRecorderState createState() => _AudioRecorderState();  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    super.debugFillProperties(properties);    properties.add(ObjectFlagProperty.has('onStop', onStop));  }}class _AudioRecorderState extends State {  bool _isRecording = false;  bool _isPaused = false;  int _recordDuration = 0;  Timer? _timer;  Timer? _ampTimer;  final FlutterSoundRecord _audioRecorder = FlutterSoundRecord();  Amplitude? _amplitude;  @override  void initState() {    _isRecording = false;    super.initState();  }  @override  void dispose() {    _timer?.cancel();    _ampTimer?.cancel();    _audioRecorder.dispose();    super.dispose();  }  @override  Widget build(BuildContext context) {    return MaterialApp(      home: Scaffold(        body: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: [            Row(              mainAxisAlignment: MainAxisAlignment.center,              children: [                _buildRecordStopControl(),                const SizedBox(width: 20),                _buildPauseResumeControl(),                const SizedBox(width: 20),                _buildText(),              ],            ),            if (_amplitude != null) ...[              const SizedBox(height: 40),              Text('Current: ${_amplitude?.current ?? 0.0}'),              Text('Max: ${_amplitude?.max ?? 0.0}'),            ],          ],        ),      ),    );  }  Widget _buildRecordStopControl() {    late Icon icon;    late Color color;    if (_isRecording || _isPaused) {      icon = const Icon(Icons.stop, color: Colors.red, size: 30);      color = Colors.red.withOpacity(0.1);    } else {      final ThemeData theme = Theme.of(context);      icon = Icon(Icons.mic, color: theme.primaryColor, size: 30);      color = theme.primaryColor.withOpacity(0.1);    }    return ClipOval(      child: Material(        color: color,        child: InkWell(          child: SizedBox(width: 56, height: 56, child: icon),          onTap: () {            _isRecording ? _stop() : _start();          },        ),      ),    );  }  Widget _buildPauseResumeControl() {    if (!_isRecording && !_isPaused) {      return const SizedBox.shrink();    }    late Icon icon;    late Color color;    if (!_isPaused) {      icon = const Icon(Icons.pause, color: Colors.red, size: 30);      color = Colors.red.withOpacity(0.1);    } else {      final ThemeData theme = Theme.of(context);      icon = const Icon(Icons.play_arrow, color: Colors.red, size: 30);      color = theme.primaryColor.withOpacity(0.1);    }    return ClipOval(      child: Material(        color: color,        child: InkWell(          child: SizedBox(width: 56, height: 56, child: icon),          onTap: () {            _isPaused ? _resume() : _pause();          },        ),      ),    );  }  Widget _buildText() {    if (_isRecording || _isPaused) {      return _buildTimer();    }    return const Text('Waiting to record');  }  Widget _buildTimer() {    final String minutes = _formatNumber(_recordDuration ~/ 60);    final String seconds = _formatNumber(_recordDuration % 60);    return Text(      '$minutes : $seconds',      style: const TextStyle(color: Colors.red),    );  }  String _formatNumber(int number) {    String numberStr = number.toString();    if (number  _isRecording = false);  }  Future _pause() async {    _timer?.cancel();    _ampTimer?.cancel();    await _audioRecorder.pause();    setState(() => _isPaused = true);  }  Future _resume() async {    _startTimer();    await _audioRecorder.resume();    setState(() => _isPaused = false);  }  void _startTimer() {    _timer?.cancel();    _ampTimer?.cancel();    _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {      setState(() => _recordDuration++);    });    _ampTimer = Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {      _amplitude = await _audioRecorder.getAmplitude();      setState(() {});    });  }}void main() {  runApp(const MyApp());}class MyApp extends StatefulWidget {  const MyApp({Key? key}) : super(key: key);  @override  _MyAppState createState() => _MyAppState();}class _MyAppState extends State {  bool showPlayer = false;  ap.AudioSource? audioSource;  @override  void initState() {    showPlayer = false;    super.initState();  }  @override  Widget build(BuildContext context) {    return MaterialApp(      home: Scaffold(        body: Center(          child: showPlayer              ? Padding(                  padding: const EdgeInsets.symmetric(horizontal: 25),                  child: AudioPlayer(                    source: audioSource!,                    onDelete: () {                      setState(() => showPlayer = false);                    },                  ),                )              : AudioRecorder(                  onStop: (String path) {                    setState(() {                      audioSource = ap.AudioSource.uri(Uri.parse(path));                      showPlayer = true;                    });                  },                ),        ),      ),    );  }  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    super.debugFillProperties(properties);    properties.add(DiagnosticsProperty('showPlayer', showPlayer));    properties.add(DiagnosticsProperty('audioSource', audioSource));  }}
          audio_player.dart
          import 'dart:async';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:just_audio/just_audio.dart' as ap;class AudioPlayer extends StatefulWidget {  const AudioPlayer({    required this.source,    required this.onDelete,    Key? key,  }) : super(key: key);  /// Path from where to play recorded audio  final ap.AudioSource source;  /// Callback when audio file should be removed  /// Setting this to null hides the delete button  final VoidCallback onDelete;  @override  AudioPlayerState createState() => AudioPlayerState();  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    super.debugFillProperties(properties);    properties.add(DiagnosticsProperty('source', source));    properties.add(ObjectFlagProperty.has('onDelete', onDelete));  }}class AudioPlayerState extends State {  static const double _controlSize = 56;  static const double _deleteBtnSize = 24;  final ap.AudioPlayer _audioPlayer = ap.AudioPlayer();  late StreamSubscription _playerStateChangedSubscription;  late StreamSubscription _durationChangedSubscription;  late StreamSubscription _positionChangedSubscription;  @override  void initState() {    _playerStateChangedSubscription = _audioPlayer.playerStateStream.listen((ap.PlayerState state) async {      if (state.processingState == ap.ProcessingState.completed) {        await stop();      }      setState(() {});    });    _positionChangedSubscription = _audioPlayer.positionStream.listen((Duration position) => setState(() {}));    _durationChangedSubscription = _audioPlayer.durationStream.listen((Duration? duration) => setState(() {}));    _init();    super.initState();  }  Future _init() async {    await _audioPlayer.setAudioSource(widget.source);  }  @override  void dispose() {    _playerStateChangedSubscription.cancel();    _positionChangedSubscription.cancel();    _durationChangedSubscription.cancel();    _audioPlayer.dispose();    super.dispose();  }  @override  Widget build(BuildContext context) {    return LayoutBuilder(      builder: (BuildContext context, BoxConstraints constraints) {        return Row(          mainAxisAlignment: MainAxisAlignment.spaceBetween,          children: [            _buildControl(),            _buildSlider(constraints.maxWidth),            IconButton(              icon: const Icon(                Icons.delete,                color: Color(0xFF73748D),                size: _deleteBtnSize,              ),              onPressed: () {                // ignore: always_specify_types                _audioPlayer.stop().then((value) => widget.onDelete());              },            ),          ],        );      },    );  }  Widget _buildControl() {    Icon icon;    Color color;    if (_audioPlayer.playerState.playing) {      icon = const Icon(Icons.pause, color: Colors.red, size: 30);      color = Colors.red.withOpacity(0.1);    } else {      final ThemeData theme = Theme.of(context);      icon = Icon(Icons.play_arrow, color: theme.primaryColor, size: 30);      color = theme.primaryColor.withOpacity(0.1);    }    return ClipOval(      child: Material(        color: color,        child: InkWell(          child: SizedBox(width: _controlSize, height: _controlSize, child: icon),          onTap: () {            if (_audioPlayer.playerState.playing) {              pause();            } else {              play();            }          },        ),      ),    );  }  Widget _buildSlider(double widgetWidth) {    final Duration position = _audioPlayer.position;    final Duration? duration = _audioPlayer.duration;    bool canSetValue = false;    if (duration != null) {      canSetValue = position.inMilliseconds > 0;      canSetValue &= position.inMilliseconds  

          源码地址

          https://github.com/josephcrowell/flutter_sound_record/

上一篇:手游卡牌源码探索,揭秘游戏世界的编程奥秘

下一篇:花雨庭服务器怎么打?