reason

华为手机保持音频失败

1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 + xmlns:tools="http://schemas.android.com/tools"
2 package="com.mofunsky.one_poem"> 3 package="com.mofunsky.one_poem">
3 <application 4 <application
5 + android:requestLegacyExternalStorage="true"
6 + tools:replace="android:label"
4 android:label="一言" 7 android:label="一言"
5 android:icon="@mipmap/ic_launcher"> 8 android:icon="@mipmap/ic_launcher">
6 <activity 9 <activity
......
...@@ -41,5 +41,12 @@ ...@@ -41,5 +41,12 @@
41 </array> 41 </array>
42 <key>UIViewControllerBasedStatusBarAppearance</key> 42 <key>UIViewControllerBasedStatusBarAppearance</key>
43 <false/> 43 <false/>
44 + <key>NSMicrophoneUsageDescription</key>
45 + <string>打开话筒</string>
46 + <key>NSAppTransportSecurity</key>
47 + <dict>
48 + <key>NSAllowsArbitraryLoads</key>
49 + <true/>
50 + </dict>
44 </dict> 51 </dict>
45 </plist> 52 </plist>
......
...@@ -73,7 +73,7 @@ class CategoryItem extends StatelessWidget { ...@@ -73,7 +73,7 @@ class CategoryItem extends StatelessWidget {
73 ], 73 ],
74 ), 74 ),
75 const Text( 75 const Text(
76 - "", 76 + "",
77 style: TextStyle( 77 style: TextStyle(
78 fontSize: 30, fontFamily: "ZhiMangXing"), 78 fontSize: 30, fontFamily: "ZhiMangXing"),
79 ), 79 ),
......
1 +
2 +import 'shared/size_fit.dart';
3 +
4 +extension DoubleFit on double {
5 + double get px {
6 + return HYSizeFit.setPx(this);
7 + }
8 +
9 + double get rpx {
10 + return HYSizeFit.setRpx(this);
11 + }
12 +}
1 +
2 +import 'shared/size_fit.dart';
3 +
4 +extension IntFit on int {
5 + double get px {
6 + return HYSizeFit.setPx(toDouble());
7 + }
8 +
9 + double get rpx {
10 + return HYSizeFit.setRpx(toDouble());
11 + }
12 +}
1 +import 'package:flutter/material.dart';
2 +
3 +class HYSizeFit {
4 + static late MediaQueryData _mediaQueryData;
5 + static late double screenWidth;
6 + static late double screenHeight;
7 + static late double rpx;
8 + static late double px;
9 +
10 + static void initialize(BuildContext context, {double standardWidth = 750}) {
11 + _mediaQueryData = MediaQuery.of(context);
12 + screenWidth = _mediaQueryData.size.width;
13 + screenHeight = _mediaQueryData.size.height;
14 + rpx = screenWidth / standardWidth;
15 + px = screenWidth / standardWidth * 2;
16 + }
17 +
18 + // 按照像素来设置
19 + static double setPx(double size) {
20 + return HYSizeFit.rpx * size * 2;
21 + }
22 +
23 + // 按照rxp来设置
24 + static double setRpx(double size) {
25 + return HYSizeFit.rpx * size;
26 + }
27 +}
...@@ -2,6 +2,7 @@ import 'dart:async'; ...@@ -2,6 +2,7 @@ import 'dart:async';
2 2
3 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
4 import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart'; 4 import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';
5 +import 'package:one_poem/extension/shared/size_fit.dart';
5 import 'package:one_poem/login/login_router.dart'; 6 import 'package:one_poem/login/login_router.dart';
6 import 'package:one_poem/res/constant.dart'; 7 import 'package:one_poem/res/constant.dart';
7 import 'package:one_poem/routers/fluro_navigator.dart'; 8 import 'package:one_poem/routers/fluro_navigator.dart';
...@@ -83,6 +84,7 @@ class _SplashPageState extends State<SplashPage> { ...@@ -83,6 +84,7 @@ class _SplashPageState extends State<SplashPage> {
83 84
84 @override 85 @override
85 Widget build(BuildContext context) { 86 Widget build(BuildContext context) {
87 + HYSizeFit.initialize(context);
86 return Material( 88 return Material(
87 color: context.backgroundColor, 89 color: context.backgroundColor,
88 child: _status == 0 ? 90 child: _status == 0 ?
......
...@@ -84,6 +84,7 @@ class _LoginPageState extends State<LoginPage> with ChangeNotifierMixin<LoginPag ...@@ -84,6 +84,7 @@ class _LoginPageState extends State<LoginPage> with ChangeNotifierMixin<LoginPag
84 return Scaffold( 84 return Scaffold(
85 appBar: MyAppBar( 85 appBar: MyAppBar(
86 isBack: false, 86 isBack: false,
87 + isTransparent: true,
87 onPressed: () { 88 onPressed: () {
88 NavigatorUtils.push(context, LoginRouter.smsLoginPage); 89 NavigatorUtils.push(context, LoginRouter.smsLoginPage);
89 }, 90 },
......
...@@ -11,6 +11,8 @@ import 'package:one_poem/widgets/bars/home_action_bar.dart'; ...@@ -11,6 +11,8 @@ import 'package:one_poem/widgets/bars/home_action_bar.dart';
11 import 'package:one_poem/widgets/bars/home_menu_bar.dart'; 11 import 'package:one_poem/widgets/bars/home_menu_bar.dart';
12 import 'package:one_poem/widgets/my_app_bar.dart'; 12 import 'package:one_poem/widgets/my_app_bar.dart';
13 13
14 +import 'package:one_poem/extension/int_extension.dart';
15 +
14 import '../poem_router.dart'; 16 import '../poem_router.dart';
15 17
16 enum PoemContentSwitch { 18 enum PoemContentSwitch {
...@@ -52,8 +54,9 @@ class _PoemDetailPageState extends State<PoemDetailPage> { ...@@ -52,8 +54,9 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
52 contentSwitch = PoemContentSwitch.comment; 54 contentSwitch = PoemContentSwitch.comment;
53 setState(() {}); 55 setState(() {});
54 }, 56 },
55 - funcRight: (){ 57 + funcRight: () {
56 - NavigatorUtils.push(context, '${PoemRouter.poemRecordAudioPage}?id=100'); 58 + NavigatorUtils.push(
59 + context, '${PoemRouter.poemRecordAudioPage}?id=100');
57 }, 60 },
58 ), 61 ),
59 homeActionWidgets: HomeActionWidgets( 62 homeActionWidgets: HomeActionWidgets(
...@@ -75,10 +78,10 @@ class _PoemDetailPageState extends State<PoemDetailPage> { ...@@ -75,10 +78,10 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
75 crossAxisAlignment: CrossAxisAlignment.start, 78 crossAxisAlignment: CrossAxisAlignment.start,
76 children: [ 79 children: [
77 Container( 80 Container(
78 - margin: const EdgeInsets.symmetric( 81 + margin:
79 - vertical: 30.0, horizontal: 20.0), 82 + EdgeInsets.symmetric(vertical: 30.px, horizontal: 20.px),
80 height: MediaQuery.of(context).size.height - 83 height: MediaQuery.of(context).size.height -
81 - 140 - 84 + 140.px -
82 widget.poemPanelHeight, 85 widget.poemPanelHeight,
83 width: double.infinity, 86 width: double.infinity,
84 decoration: BoxDecoration( 87 decoration: BoxDecoration(
...@@ -97,7 +100,7 @@ class _PoemDetailPageState extends State<PoemDetailPage> { ...@@ -97,7 +100,7 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
97 color: Colors.grey.shade200.withOpacity(0.1), 100 color: Colors.grey.shade200.withOpacity(0.1),
98 ), 101 ),
99 child: Padding( 102 child: Padding(
100 - padding: const EdgeInsets.all(10.0), 103 + padding: EdgeInsets.all(10.px),
101 child: Flex( 104 child: Flex(
102 direction: Axis.vertical, 105 direction: Axis.vertical,
103 children: [ 106 children: [
...@@ -109,7 +112,9 @@ class _PoemDetailPageState extends State<PoemDetailPage> { ...@@ -109,7 +112,9 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
109 Expanded( 112 Expanded(
110 flex: 1, 113 flex: 1,
111 child: contentSwitch == PoemContentSwitch.audio 114 child: contentSwitch == PoemContentSwitch.audio
112 - ? const PoemUserAudio() 115 + ? PoemUserAudio(
116 + poemPanelHeight: widget.poemPanelHeight,
117 + )
113 : const PoemUserComments( 118 : const PoemUserComments(
114 author: "老魔取西经", 119 author: "老魔取西经",
115 comments: 120 comments:
...@@ -124,17 +129,17 @@ class _PoemDetailPageState extends State<PoemDetailPage> { ...@@ -124,17 +129,17 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
124 mainAxisSize: MainAxisSize.min, 129 mainAxisSize: MainAxisSize.min,
125 children: [ 130 children: [
126 IconButton( 131 IconButton(
127 - icon: const Icon( 132 + icon: Icon(
128 Icons.mic_none, 133 Icons.mic_none,
129 - size: 36.0, 134 + size: 36.px,
130 ), 135 ),
131 onPressed: () {}, 136 onPressed: () {},
132 ), 137 ),
133 Gaps.hGap16, 138 Gaps.hGap16,
134 IconButton( 139 IconButton(
135 - icon: const Icon( 140 + icon: Icon(
136 Icons.camera_alt_outlined, 141 Icons.camera_alt_outlined,
137 - size: 36.0, 142 + size: 36.px,
138 ), 143 ),
139 onPressed: () {}, 144 onPressed: () {},
140 ) 145 )
......
...@@ -3,11 +3,13 @@ import 'dart:ui'; ...@@ -3,11 +3,13 @@ import 'dart:ui';
3 import 'package:flutter/cupertino.dart'; 3 import 'package:flutter/cupertino.dart';
4 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
5 import 'package:one_poem/poem/widgets/poem_content.dart'; 5 import 'package:one_poem/poem/widgets/poem_content.dart';
6 -import 'package:one_poem/res/resources.dart'; 6 +import 'package:one_poem/recorder/widgets/poem_voice_widget.dart';
7 import 'package:one_poem/widgets/bars/home_action_bar.dart'; 7 import 'package:one_poem/widgets/bars/home_action_bar.dart';
8 import 'package:one_poem/widgets/bars/home_menu_bar.dart'; 8 import 'package:one_poem/widgets/bars/home_menu_bar.dart';
9 import 'package:one_poem/widgets/my_app_bar.dart'; 9 import 'package:one_poem/widgets/my_app_bar.dart';
10 10
11 +import 'package:one_poem/extension/int_extension.dart';
12 +
11 class PoemRecordAudioPage extends StatefulWidget { 13 class PoemRecordAudioPage extends StatefulWidget {
12 @override 14 @override
13 State<StatefulWidget> createState() => _PoemRecordAudioPageState(); 15 State<StatefulWidget> createState() => _PoemRecordAudioPageState();
...@@ -23,6 +25,16 @@ class PoemRecordAudioPage extends StatefulWidget { ...@@ -23,6 +25,16 @@ class PoemRecordAudioPage extends StatefulWidget {
23 } 25 }
24 26
25 class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { 27 class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> {
28 + startRecord() {
29 + print("开始录制");
30 + }
31 +
32 + stopRecord(String path, double audioTimeLength) {
33 + print("结束束录制");
34 + print("音频文件位置" + path);
35 + print("音频录制时长" + audioTimeLength.toString());
36 + }
37 +
26 @override 38 @override
27 Widget build(BuildContext context) { 39 Widget build(BuildContext context) {
28 const poemStr = 40 const poemStr =
...@@ -59,10 +71,10 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { ...@@ -59,10 +71,10 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> {
59 crossAxisAlignment: CrossAxisAlignment.start, 71 crossAxisAlignment: CrossAxisAlignment.start,
60 children: [ 72 children: [
61 Container( 73 Container(
62 - margin: const EdgeInsets.symmetric( 74 + margin:
63 - vertical: 30.0, horizontal: 20.0), 75 + EdgeInsets.symmetric(vertical: 20.px, horizontal: 20.px),
64 height: MediaQuery.of(context).size.height - 76 height: MediaQuery.of(context).size.height -
65 - 140 - 77 + 110.px -
66 widget.poemPanelHeight, 78 widget.poemPanelHeight,
67 width: double.infinity, 79 width: double.infinity,
68 decoration: BoxDecoration( 80 decoration: BoxDecoration(
...@@ -81,39 +93,37 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { ...@@ -81,39 +93,37 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> {
81 color: Colors.grey.shade200.withOpacity(0.1), 93 color: Colors.grey.shade200.withOpacity(0.1),
82 ), 94 ),
83 child: Padding( 95 child: Padding(
84 - padding: const EdgeInsets.all(10.0), 96 + padding: EdgeInsets.all(10.px),
85 child: Flex( 97 child: Flex(
86 direction: Axis.vertical, 98 direction: Axis.vertical,
87 children: [ 99 children: [
88 - const PoemContent( 100 + PoemContent(
89 title: "题破山寺后禅院", 101 title: "题破山寺后禅院",
90 author: "常建", 102 author: "常建",
91 poemStr: poemStr, 103 poemStr: poemStr,
92 - fontSize: 22.0, 104 + fontSize: 20.px,
93 ), 105 ),
94 Stack( 106 Stack(
95 alignment: Alignment.center, 107 alignment: Alignment.center,
96 children: [ 108 children: [
97 Positioned( 109 Positioned(
98 - left: 10.0, 110 + left: 10.px,
99 child: IconButton( 111 child: IconButton(
100 - icon: const Icon( 112 + icon: Icon(
101 Icons.camera_alt_outlined, 113 Icons.camera_alt_outlined,
102 - size: 28.0, 114 + size: 28.px,
103 ), 115 ),
104 onPressed: () {}, 116 onPressed: () {},
105 ), 117 ),
106 ), 118 ),
107 SizedBox( 119 SizedBox(
108 width: double.infinity, 120 width: double.infinity,
109 - height: 90.0, 121 + height: 80.px,
110 - child: IconButton( 122 + child: PoemVoiceWidget(
111 - icon: const Icon( 123 + startRecord: startRecord,
112 - Icons.mic_none, 124 + stopRecord: stopRecord,
113 - size: 70.0, 125 + // 加入定制化Container的相关属性
114 - color: Colors.green, 126 + height: 40.px,
115 - ),
116 - onPressed: () {},
117 ), 127 ),
118 ), 128 ),
119 ], 129 ],
......
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 3
4 +import 'package:one_poem/extension/int_extension.dart';
5 +
4 class PoemUserAudio extends StatelessWidget { 6 class PoemUserAudio extends StatelessWidget {
5 const PoemUserAudio({ 7 const PoemUserAudio({
6 Key? key, 8 Key? key,
7 this.audio, //TODO 传入数据 9 this.audio, //TODO 传入数据
8 this.desc, 10 this.desc,
11 + this.poemPanelHeight = 0,
9 }) : super(key: key); 12 }) : super(key: key);
10 13
11 final List<Map<String, String>>? audio; 14 final List<Map<String, String>>? audio;
12 final String? desc; 15 final String? desc;
16 + final int poemPanelHeight;
13 @override 17 @override
14 Widget build(BuildContext context) { 18 Widget build(BuildContext context) {
15 return Container( 19 return Container(
16 - padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), 20 + padding: EdgeInsets.symmetric(vertical: 5.px, horizontal: 10.px),
17 width: double.infinity, 21 width: double.infinity,
18 child: Column( 22 child: Column(
19 children: <Widget>[ 23 children: <Widget>[
20 ListTile( 24 ListTile(
21 title: Text( 25 title: Text(
22 desc ?? "一大波用户朗读录制提交了“临境”", 26 desc ?? "一大波用户朗读录制提交了“临境”",
23 - style: const TextStyle(color: Colors.black54, fontSize: 15.0), 27 + style: TextStyle(color: Colors.black54, fontSize: 15.px),
24 ), 28 ),
25 ), 29 ),
26 SizedBox( 30 SizedBox(
27 width: double.infinity, 31 width: double.infinity,
28 - height: 200.0, 32 + height: 200.px - poemPanelHeight,
29 child: ListView.builder( 33 child: ListView.builder(
30 itemBuilder: (BuildContext context, int index) { 34 itemBuilder: (BuildContext context, int index) {
31 return Wrap( 35 return Wrap(
32 - spacing: 5.0, 36 + spacing: 5.px,
33 crossAxisAlignment: WrapCrossAlignment.center, 37 crossAxisAlignment: WrapCrossAlignment.center,
34 - children: const [ 38 + children: [
35 Icon( 39 Icon(
36 Icons.play_circle_outline, 40 Icons.play_circle_outline,
37 - size: 16.0, 41 + size: 16.px,
38 color: Colors.black45, 42 color: Colors.black45,
39 ), 43 ),
40 - Text( 44 + const Text(
41 "普通话", 45 "普通话",
42 style: TextStyle(color: Colors.black45, fontSize: 16.0), 46 style: TextStyle(color: Colors.black45, fontSize: 16.0),
43 ) 47 )
......
1 +import 'package:flutter/material.dart';
2 +
3 +class CustomOverlay extends StatelessWidget {
4 + final Widget? icon;
5 + final BoxDecoration decoration;
6 + final double width;
7 + final double height;
8 + const CustomOverlay({
9 + Key? key,
10 + this.icon,
11 + this.decoration = const BoxDecoration(
12 + color: Color(0xff77797A),
13 + borderRadius: BorderRadius.all(Radius.circular(20.0)),
14 + ),
15 + this.width = 160,
16 + this.height = 160,
17 + }) : super(key: key);
18 +
19 + @override
20 + Widget build(BuildContext context) {
21 + return Positioned(
22 + top: MediaQuery.of(context).size.height * 0.5 - width / 2,
23 + left: MediaQuery.of(context).size.width * 0.5 - height / 2,
24 + child: Material(
25 + type: MaterialType.transparency,
26 + child: Center(
27 + child: Opacity(
28 + opacity: 0.8,
29 + child: Container(
30 + width: width,
31 + height: height,
32 + decoration: decoration,
33 + child: icon,
34 + ),
35 + ),
36 + ),
37 + ),
38 + );
39 + }
40 +}
1 +import 'dart:async';
2 +
3 +import 'package:flutter/material.dart';
4 +import 'package:flutter_plugin_record/flutter_plugin_record.dart';
5 +import 'package:flutter_plugin_record/utils/common_toast.dart';
6 +
7 +import 'custom_overlay.dart';
8 +
9 +typedef StartRecord = Future Function();
10 +typedef StopRecord = Future Function();
11 +
12 +class PoemVoiceWidget extends StatefulWidget {
13 + final Function? startRecord;
14 + final Function? stopRecord;
15 + final double? height;
16 + final EdgeInsets? margin;
17 + final Decoration? decoration;
18 +
19 + /// startRecord 开始录制回调 stopRecord回调
20 + const PoemVoiceWidget(
21 + {Key? key,
22 + this.startRecord,
23 + this.stopRecord,
24 + this.height,
25 + this.decoration,
26 + this.margin})
27 + : super(key: key);
28 +
29 + @override
30 + _PoemVoiceWidgetState createState() => _PoemVoiceWidgetState();
31 +}
32 +
33 +class _PoemVoiceWidgetState extends State<PoemVoiceWidget> {
34 + // 倒计时总时长
35 + final int _countTotal = 12;
36 + double starty = 0.0;
37 + double offset = 0.0;
38 + bool isUp = false;
39 + String textShow = "按住说话";
40 + String toastShow = "手指上滑,取消发送";
41 + String voiceIco = "images/voice_volume_1.png";
42 +
43 + ///默认隐藏状态
44 + bool voiceState = true;
45 + FlutterPluginRecord? recordPlugin;
46 + Timer? _timer;
47 + int _count = 0;
48 + OverlayEntry? overlayEntry;
49 +
50 + String audioFilePath = "";
51 +
52 + @override
53 + void initState() {
54 + super.initState();
55 + recordPlugin = FlutterPluginRecord();
56 +
57 + _init();
58 +
59 + ///初始化方法的监听
60 + recordPlugin?.responseFromInit.listen((data) {
61 + // if (data) {
62 + // print("初始化成功");
63 + // } else {
64 + // print("初始化失败");
65 + // }
66 + });
67 +
68 + /// 开始录制或结束录制的监听
69 + recordPlugin?.response.listen((data) {
70 + if (data.msg == "onStop") {
71 + ///结束录制时会返回录制文件的地址方便上传服务器
72 + // print("onStop " + data.path!);
73 + if (widget.stopRecord != null) {
74 + audioFilePath = data.path!;
75 + widget.stopRecord!(data.path, data.audioTimeLength);
76 + }
77 + } else if (data.msg == "onStart") {
78 + if (widget.startRecord != null) widget.startRecord!();
79 + }
80 + });
81 +
82 + ///录制过程监听录制的声音的大小 方便做语音动画显示图片的样式
83 + recordPlugin!.responseFromAmplitude.listen((data) {
84 + var voiceData = double.parse(data.msg ?? '');
85 + setState(() {
86 + if (voiceData > 0 && voiceData < 0.1) {
87 + voiceIco = "images/voice_volume_2.png";
88 + } else if (voiceData > 0.2 && voiceData < 0.3) {
89 + voiceIco = "images/voice_volume_3.png";
90 + } else if (voiceData > 0.3 && voiceData < 0.4) {
91 + voiceIco = "images/voice_volume_4.png";
92 + } else if (voiceData > 0.4 && voiceData < 0.5) {
93 + voiceIco = "images/voice_volume_5.png";
94 + } else if (voiceData > 0.5 && voiceData < 0.6) {
95 + voiceIco = "images/voice_volume_6.png";
96 + } else if (voiceData > 0.6 && voiceData < 0.7) {
97 + voiceIco = "images/voice_volume_7.png";
98 + } else if (voiceData > 0.7 && voiceData < 1) {
99 + voiceIco = "images/voice_volume_7.png";
100 + } else {
101 + voiceIco = "images/voice_volume_1.png";
102 + }
103 + if (overlayEntry != null) {
104 + overlayEntry!.markNeedsBuild();
105 + }
106 + });
107 +
108 + // print("振幅大小 " + voiceData.toString() + " " + voiceIco);
109 + });
110 + }
111 +
112 + ///显示录音悬浮布局
113 + buildOverLayView(BuildContext context) {
114 + if (overlayEntry == null) {
115 + overlayEntry = OverlayEntry(builder: (content) {
116 + return CustomOverlay(
117 + icon: Column(
118 + children: <Widget>[
119 + Container(
120 + margin: const EdgeInsets.only(top: 10),
121 + child: _countTotal - _count < 11
122 + ? Center(
123 + child: Padding(
124 + padding: const EdgeInsets.only(bottom: 15.0),
125 + child: Text(
126 + (_countTotal - _count).toString(),
127 + style: const TextStyle(
128 + fontSize: 70.0,
129 + color: Colors.white,
130 + ),
131 + ),
132 + ),
133 + )
134 + : Image.asset(
135 + voiceIco,
136 + width: 100,
137 + height: 100,
138 + package: 'flutter_plugin_record',
139 + ),
140 + ),
141 + Text(
142 + toastShow,
143 + style: const TextStyle(
144 + fontStyle: FontStyle.normal,
145 + color: Colors.white,
146 + fontSize: 14,
147 + ),
148 + )
149 + ],
150 + ),
151 + );
152 + });
153 + Overlay.of(context)!.insert(overlayEntry!);
154 + }
155 + }
156 +
157 + showVoiceView() {
158 + setState(() {
159 + textShow = "松开结束";
160 + voiceState = false;
161 + });
162 +
163 + ///显示录音悬浮布局
164 + buildOverLayView(context);
165 +
166 + start();
167 + }
168 +
169 + hideVoiceView() {
170 + if (_timer!.isActive) {
171 + if (_count < 1) {
172 + CommonToast.showView(
173 + context: context,
174 + msg: '说话时间太短',
175 + icon: const Text(
176 + '!',
177 + style: TextStyle(fontSize: 80, color: Colors.white),
178 + ));
179 + isUp = true;
180 + }
181 + _timer?.cancel();
182 + _count = 0;
183 + }
184 +
185 + setState(() {
186 + textShow = "按住说话";
187 + voiceState = true;
188 + });
189 +
190 + stop();
191 + if (overlayEntry != null) {
192 + overlayEntry?.remove();
193 + overlayEntry = null;
194 + }
195 +
196 + // if (isUp) {
197 + // print("取消发送");
198 + // } else {
199 + // print("进行发送");
200 + // }
201 + }
202 +
203 + moveVoiceView() {
204 + setState(() {
205 + isUp = starty - offset > 100 ? true : false;
206 + if (isUp) {
207 + textShow = "松开手指,取消发送";
208 + toastShow = textShow;
209 + } else {
210 + textShow = "松开结束";
211 + toastShow = "手指上滑,取消发送";
212 + }
213 + });
214 + }
215 +
216 + ///初始化语音录制的方法
217 + void _init() async {
218 + recordPlugin?.initRecordMp3();
219 + }
220 +
221 + ///开始语音录制的方法
222 + void start() async {
223 + recordPlugin?.start();
224 + }
225 +
226 + ///停止语音录制的方法
227 + void stop() {
228 + recordPlugin?.stop();
229 + }
230 +
231 + @override
232 + Widget build(BuildContext context) {
233 + return Padding(
234 + padding: const EdgeInsets.only(right: 10.0),
235 + child: Row(
236 + crossAxisAlignment: CrossAxisAlignment.center,
237 + mainAxisAlignment: MainAxisAlignment.end,
238 + children: [
239 + GestureDetector(
240 + onLongPressStart: (details) {
241 + starty = details.globalPosition.dy;
242 + _timer = Timer.periodic(const Duration(milliseconds: 1000), (t) {
243 + _count++;
244 + if (_count == _countTotal) {
245 + hideVoiceView();
246 + }
247 + });
248 + showVoiceView();
249 + },
250 + onLongPressEnd: (details) {
251 + hideVoiceView();
252 + },
253 + onLongPressMoveUpdate: (details) {
254 + offset = details.globalPosition.dy;
255 + moveVoiceView();
256 + },
257 + child: Container(
258 + height: widget.height ?? 60,
259 + margin: widget.margin ?? const EdgeInsets.fromLTRB(50, 0, 50, 20),
260 + child: const Icon(
261 + Icons.mic_none,
262 + size: 70.0,
263 + color: Colors.green,
264 + ),
265 + ),
266 + ),
267 + IconButton(
268 + icon: const Icon(
269 + Icons.play_circle_outline,
270 + size: 28.0,
271 + ),
272 + onPressed: () {
273 + print("######:" + audioFilePath);
274 + recordPlugin!.playByPath(audioFilePath, "file");
275 + },
276 + ),
277 + ],
278 + ),
279 + );
280 + }
281 +
282 + @override
283 + void dispose() {
284 + recordPlugin?.dispose();
285 + _timer?.cancel();
286 + super.dispose();
287 + }
288 +}
...@@ -366,6 +366,13 @@ packages: ...@@ -366,6 +366,13 @@ packages:
366 url: "https://pub.dartlang.org" 366 url: "https://pub.dartlang.org"
367 source: hosted 367 source: hosted
368 version: "2.0.5" 368 version: "2.0.5"
369 + flutter_plugin_record:
370 + dependency: "direct main"
371 + description:
372 + name: flutter_plugin_record
373 + url: "https://pub.dartlang.org"
374 + source: hosted
375 + version: "1.0.1"
369 flutter_slidable: 376 flutter_slidable:
370 dependency: "direct main" 377 dependency: "direct main"
371 description: 378 description:
......
...@@ -91,6 +91,7 @@ dependencies: ...@@ -91,6 +91,7 @@ dependencies:
91 flutter_spinkit: ^5.0.0 91 flutter_spinkit: ^5.0.0
92 92
93 json_annotation: ^4.4.0 93 json_annotation: ^4.4.0
94 + flutter_plugin_record: ^1.0.1
94 95
95 dependency_overrides: 96 dependency_overrides:
96 decimal: 1.5.0 97 decimal: 1.5.0
......