我正在 Dart 中编写 ChatApp,在使用以下方法编写自定义语音消息小部件时发现了一个问题:
audio_waveforms: ^1.0.5
我已经这样做了,但我没有找到一种方法来缓存语音消息小部件,这会导致加载时间很长,当您发送新的语音消息时,它会刹车,它会创建一条新消息,但它包含上面的消息和只有在您重新渲染聊天页面后,它才会自行纠正。这是代码:
import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
class AudioMessageBeta extends StatefulWidget {
final String id;
final String audioUrl;
final String message;
const AudioMessageBeta(
{super.key,
required this.audioUrl,
required this.message,
required this.id});
@override
State<AudioMessageBeta> createState() => _AudioMessageBetaState();
}
class _AudioMessageBetaState extends State<AudioMessageBeta> {
bool isLoading = false;
final PlayerController playerController = new PlayerController();
StreamSubscription<PlayerState>? playerStateSubsription;
Future<dynamic> downloadFile(String url) async {
String dir = (await getApplicationDocumentsDirectory()).path;
if (await File("$dir/${widget.id}.mp3").exists()) {
return "$dir/${widget.id}.mp3";
} else {
File file = File("$dir/${widget.id}.mp3");
var request = await http.get(
Uri.parse(url),
);
var bytes = request.bodyBytes;
await file.writeAsBytes(bytes);
return file.path;
}
}
void prepareVoice() async {
await playerController.preparePlayer(
path: await downloadFile(widget.audioUrl),
shouldExtractWaveform: true,
noOfSamples: (MediaQuery.of(context).size.width * 0.5) ~/ 5);
}
@override
void initState() {
isLoading = true;
Future.delayed(const Duration(milliseconds: 200), () {
prepareVoice();
playerStateSubsription =
playerController.onPlayerStateChanged.listen((PlayerState) {
setState(() {});
});
});
super.initState();
isLoading = false;
}
@override
void dispose() {
if (mounted) {
playerController.dispose();
playerStateSubsription!.cancel();
}
super.dispose();
}
void playVoice() async {
switch (playerController.playerState) {
case PlayerState.playing:
await playerController.pausePlayer();
break;
default:
await playerController.startPlayer(finishMode: FinishMode.pause);
}
}
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.75,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListTile(
contentPadding: const EdgeInsets.all(0),
horizontalTitleGap: 8,
leading: GestureDetector(
onTap: () => playVoice(),
child: SizedBox(
height: 45,
width: 45,
child: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.background,
child: isLoading
? const CircularProgressIndicator()
: Icon(playerController.playerState.isPlaying
? Icons.pause_rounded
: Icons.play_arrow),
),
),
),
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: AudioFileWaveforms(
size: Size(MediaQuery.of(context).size.width * 0.5, 25),
playerController: playerController,
enableSeekGesture: true,
continuousWaveform: false,
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Theme.of(context).colorScheme.background,
liveWaveColor: Colors.white,
spacing: 5,
waveThickness: 2.5,
scaleFactor: 200,
),
),
),
),
),
);
}
}
我尝试了几种方法,但我无法让它工作,我也是 Flutter 的新手。
您应该将密钥传递给小部件;它防止了元素树、部件树和渲染对象树之间发生的冲突。
例如:
AudioMessageBeta(
key: ValueKey(id),
audioUrl: 'your_audio_url',
message: 'your_message'
),
这些资源将帮助您加深对该主题的理解:
https://abhishekdoshi26.medium.com/deep-dive-into-flutter-trees-542f7395df5c https://www.youtube.com/watch?v=kn0EOS-ZiIc&ab_channel=GoogleforDevelopers https://medium.com/@yetesfadev/understanding-keys-in-dart-and-flutter-use-cases-examples-advantages-and-disadvantages-efff26b2d6e8