//这里的方法就是:可以先在Widget build写一部分,用Expanded把Material的控件放底下,然后再用Material(child: _buildPlayer()),显示其他界面,可以在_buildPlayer方法体里面放其他方法体,可以用列的方式排序,方法体的写法要学会
方法体如下
Row _buildMuteButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
if (!isMuted)
FlatButton.icon(
onPressed: () => mute(true),
icon: Icon(
Icons.headset_off,
color: Colors.cyan,
),
label: Text('Mute', style: TextStyle(color: Colors.cyan)),
),
if (isMuted)
FlatButton.icon(
onPressed: () => mute(false),
icon: Icon(Icons.headset, color: Colors.cyan),
label: Text('Unmute', style: TextStyle(color: Colors.cyan)),
),
],
);
}
import 'dart:async';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
//音乐播放器
typedef void OnError(Exception exception);
// const kUrl =
// "https://www.mediacollege.com/downloads/sound-effects/nature/forest/rainforest-ambient.mp3";
const kUrl = "https://s3.amazonaws.com/scifri-segments/scifri201711241.mp3";
enum PlayerState { stopped, playing, paused }
class AudioPlay extends StatefulWidget {
const AudioPlay({Key key}) : super(key: key);
@override
_AudioPlayState createState() => _AudioPlayState();
}
class _AudioPlayState extends State<AudioPlay> {
Duration duration;
Duration position;
AudioPlayer audioPlayer;
String localFilePath;
PlayerState playerState = PlayerState.stopped;
get isPlaying => playerState == PlayerState.playing;
get isPaused => playerState == PlayerState.paused;
get durationText =>
duration != null ? duration.toString().split('.').first : '';
get positionText =>
position != null ? position.toString().split('.').first : '';
bool isMuted = false;
StreamSubscription _positionSubscription;
StreamSubscription _audioPlayerStateSubscription;
@override
void initState() {
super.initState();
initAudioPlayer();
}
@override
void dispose() {
_positionSubscription.cancel();
_audioPlayerStateSubscription.cancel();
audioPlayer.stop();
super.dispose();
}
void initAudioPlayer() {
audioPlayer = AudioPlayer();
_positionSubscription = audioPlayer.onAudioPositionChanged
.listen((p) => setState(() => position = p));
_audioPlayerStateSubscription =
audioPlayer.onPlayerStateChanged.listen((s) {
if (s == AudioPlayerState.PLAYING) {
setState(() => duration = audioPlayer.duration);
} else if (s == AudioPlayerState.STOPPED) {
onComplete();
setState(() {
position = duration;
});
}
}, onError: (msg) {
setState(() {
playerState = PlayerState.stopped;
duration = Duration(seconds: 0);
position = Duration(seconds: 0);
});
});
}
//播放
Future play() async {
await audioPlayer.play(kUrl);
setState(() {
playerState = PlayerState.playing;
});
}
Future _playLocal() async {
await audioPlayer.play(localFilePath, isLocal: true);
setState(() => playerState = PlayerState.playing);
}
//暂停
Future pause() async {
await audioPlayer.pause();
setState(() => playerState = PlayerState.paused);
}
//停止
Future stop() async {
await audioPlayer.stop();
setState(() {
playerState = PlayerState.stopped;
position = Duration();
});
}
Future mute(bool muted) async {
await audioPlayer.mute(muted);
setState(() {
isMuted = muted;
});
}
void onComplete() {
setState(() => playerState = PlayerState.stopped);
}
// Future _loadFile() async {
// final bytes = await _loadFileBytes(kUrl,
// onError: (Exception exception) =>
// print('_loadFile => exception $exception'));
//
// final dir = await getApplicationDocumentsDirectory();
// final file = File('${dir.path}/audio.mp3');
//
// await file.writeAsBytes(bytes);
// if (await file.exists())
// setState(() {
// localFilePath = file.path;
// });
// }
//这里的方法就是:可以先写一部分,然后再用Material(child: _buildPlayer()),显示其他界面,
// 可以在_buildPlayer里面放其他方法体
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Center(
child: Center(
child: Container(
decoration: BoxDecoration(color: Color(0xFF1F1F1F)),
//整个界面以列的形式排放
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
//封面,同时把按键放到底部
Expanded(
child: Column(
children: [
Container(
// decoration: BoxDecoration(color: Colors.black),
child: Text(
'',
),
),
Container(
margin: const EdgeInsets.only(left: 15, right: 15),
child: Image.asset(
'assets/base_widgets/bg_player.png',
fit: BoxFit.fitWidth,
),
),
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.only(
left: 30, top: 30, bottom: 15),
child: Text("Mojito",
style: TextStyle(
color: Color(0xFFCCCCCC), fontSize: 20)),
),
Row(
children: [
Container(
margin:
const EdgeInsets.only(left: 30, bottom: 12),
child: Text(
"周杰倫",
style: TextStyle(color: Color(0xFF999999)),
),
),
Container(
width: 30,
margin:
const EdgeInsets.only(left: 15, bottom: 12),
child: Image.asset(
'assets/base_widgets/icon_player_vip.png',
fit: BoxFit.fitWidth,
),
),
Container(
width: 30,
margin:
const EdgeInsets.only(left: 15, bottom: 12),
child: Image.asset(
'assets/base_widgets/icon_player_standard.png',
fit: BoxFit.fitWidth,
),
),
],
),
Container(
margin: const EdgeInsets.only(left: 30, bottom: 12),
child: Text("麻烦给我的爱人来一杯Mojito",
style: TextStyle(color: Color(0xFF666666))),
),
Container(
margin: const EdgeInsets.only(left: 30, bottom: 12),
child: Text("我喜欢阅读她微醺时的眼眸",
style: TextStyle(color: Color(0xFFFFFFFF))),
),
Container(
margin: const EdgeInsets.only(left: 30, bottom: 12),
child: Text("而我的咖啡糖不用太多",
style: TextStyle(color: Color(0xFF666666))),
),
],
),
),
],
),
),
//接着来到这里叫开始调用方法了
Material(child: _buildPlayer()),
if (!kIsWeb)
localFilePath != null ? Text(localFilePath) : Container(),
// if (!kIsWeb)
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// children: [
// RaisedButton(
// // onPressed: () => _loadFile(),
// child: Text('Download'),
// ),
// if (localFilePath != null)
// RaisedButton(
// onPressed: () => _playLocal(),
// child: Text('play local'),
// ),
// ],
// ),
// ),
],
),
),
),
);
// return MaterialApp(
// home: Scaffold(
// body: Container(
// child: ListView(
// children: [inputTextArea, loginButtonArea, loginSection],
// ),
// ),
// ));
}
Widget _buildPlayer() => Container(
decoration: BoxDecoration(color: Color(0xFF1F1F1F)),
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buttonMenuSection(),
if (duration != null)
//进度条
Slider(
value: position?.inMilliseconds?.toDouble() ?? 0.0,
onChanged: (double value) {
return audioPlayer.seek((value / 1000).roundToDouble());
},
min: 0.0,
max: duration.inMilliseconds.toDouble()),
//如果是空的就显示个空进度条
if (duration == null)
Slider(
value: position?.inMilliseconds?.toDouble() ?? 0.0,
),
//进度条
_buildProgressView(),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//循环
Container(
width: 40,
margin: const EdgeInsets.only(left: 15, right: 15),
child: Image.asset(
'assets/base_widgets/icon_player_cycle.png',
fit: BoxFit.fitWidth,
),
),
//上一首
GestureDetector(
onTap: isPlaying ? () => pause() : () => play(),
child: Container(
width: 40,
margin: const EdgeInsets.only(left: 15, right: 15),
child: Image.asset(
'assets/base_widgets/icon_player_previous.png',
fit: BoxFit.fitWidth,
),
),
),
//播放
GestureDetector(
onTap: isPlaying ? () => pause() : () => play(),
child: Container(
width: 50,
margin: const EdgeInsets.only(left: 15, right: 15),
child: Image.asset(
'assets/base_widgets/icon_player_play.png',
fit: BoxFit.fitWidth,
),
),
),
//下一首
GestureDetector(
onTap: isPlaying ? () => pause() : () => play(),
child: Container(
width: 40,
margin: const EdgeInsets.only(left: 15, right: 15),
child: Image.asset(
'assets/base_widgets/icon_player_next.png',
fit: BoxFit.fitWidth,
),
),
),
//均衡器
Container(
width: 40,
margin: const EdgeInsets.only(left: 15, right: 15),
child: Image.asset(
'assets/base_widgets/icon_player_tuning.png',
fit: BoxFit.fitWidth,
),
),
// IconButton(
// onPressed: isPlaying ? null : () => play(),
// iconSize: 64.0,
// icon: Icon(Icons.play_arrow),
// color: Colors.cyan,
// ),
// IconButton(
// onPressed: isPlaying ? () => pause() : null,
// iconSize: 64.0,
// icon: Icon(Icons.pause),
// color: Colors.cyan,
// ),
// IconButton(
// onPressed: isPlaying || isPaused ? () => stop() : null,
// iconSize: 64.0,
// icon: Icon(Icons.stop),
// color: Colors.cyan,
// ),
]),
// if (position != null)
//静音
// _buildMuteButtons(),
// if (position != null)
],
),
);
Row _buildProgressView() =>
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Container(
margin: const EdgeInsets.only(left: 15),
child: Text(
position != null
? "${positionText ?? ''} "
: duration != null
? durationText
: '',
style: TextStyle(fontSize: 12.0, color: Colors.white),
),
),
Container(
margin: const EdgeInsets.only(left: 15),
child: Text(
position != null
? "${durationText ?? ''}"
: duration != null
? durationText
: '',
style: TextStyle(fontSize: 12.0, color: Colors.white),
)),
// Padding(
// padding: EdgeInsets.all(12.0),
//圆形进度条
// child: CircularProgressIndicator(
// value: position != null && position.inMilliseconds > 0
// ? (position?.inMilliseconds?.toDouble() ?? 0.0) /
// (duration?.inMilliseconds?.toDouble() ?? 0.0)
// : 0.0,
// valueColor: AlwaysStoppedAnimation(Colors.cyan),
// backgroundColor: Colors.grey.shade400,
// ),
// ),
// Text(
// position != null
// ? "${positionText ?? ''} / ${durationText ?? ''}"
// : duration != null
// ? durationText
// : '',
// style: TextStyle(fontSize: 24.0, color: Colors.white),
// )
]);
//是否静音
Row _buildMuteButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
if (!isMuted)
FlatButton.icon(
onPressed: () => mute(true),
icon: Icon(
Icons.headset_off,
color: Colors.cyan,
),
label: Text('Mute', style: TextStyle(color: Colors.cyan)),
),
if (isMuted)
FlatButton.icon(
onPressed: () => mute(false),
icon: Icon(Icons.headset, color: Colors.cyan),
label: Text('Unmute', style: TextStyle(color: Colors.cyan)),
),
],
);
}
//上面图片下面文字的那一排按键的方法
Column menuButtonColumn(String icon, String label) {
//嵌套函数:把共同的属性写好,方便buttonSection调用
//设置为主题颜色
Color color = const Color(0xFF999999);
//返回列的形式
return Column(
//调用该方法后返回这个显示,每个元素以列的方式显示
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
//有两个元素
children: [
Image.asset(
icon,
height: 45.0,
fit: BoxFit.cover,
),
Container(
//将文字设置为容器,设置边距
margin: const EdgeInsets.only(top: 8.0), //文字距离上面图标的距离
child: Text(
//元素就是一个文字
label,
style: TextStyle(
//设置文字风格
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: color,
),
),
)
],
);
}
//底部那一排五个按键
Row buttonMenuSection() {
//先从行上开始进行分析
return Row(
//平均的分配每个列占据的行空间
mainAxisAlignment: MainAxisAlignment.spaceBetween,
//行上的四个元素
//调用方法,不然要写很多
children: [
menuButtonColumn("assets/base_widgets/icon_player_cover.png", '翻唱'),
menuButtonColumn(
"assets/base_widgets/icon_player_equalizer.png", '均衡器'),
menuButtonColumn(
"assets/base_widgets/icon_player_member_download.png", '下載'),
menuButtonColumn("assets/base_widgets/icon_player_comment.png", '評論'),
menuButtonColumn("assets/base_widgets/icon_player_more.png", '更多'),
],
);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)