return new Transform(
transform: transform,
alignment: alignment,
child: child,
);
}
}
接下来就是自定义黑胶唱头组件。
final _rotateTween = new Tween(begin: -0.15, end: 0.0);
new Container(
child: new PivotTransition(
turns: _rotateTween.animate(controller_needle),
alignment: FractionalOffset.topLeft,
child: new Container(
width: 100.0,
child: new Image.asset(“images/play_needle.png”),
),
),
),
将png图片包裹在container内作为child参数传递给PivotTransition
。
外部使用的时候传入一个Tween,起始位置为-0.15 ~ 0.0。
3.黑胶唱片的旋转动画
这部分代码在record_anim.dart
文件内。使用了package:flutter/animation.dart
提供的RotationTransition
做旋转,很简单。
class RotateRecord extends AnimatedWidget {
RotateRecord({Key key, Animation animation})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation animation = listenable;
return new Container(
margin: new EdgeInsets.symmetric(vertical: 10.0),
height: 250.0,
width: 250.0,
child: new RotationTransition(
turns: animation,
child: new Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
“https://images-na.ssl-images-amazon.com/images/I/51inO4DBH0L._SS500.jpg”),
),
),
)),
);
}
}
接着自定义旋转动画的控制逻辑。旋转一圈用时十五秒钟,速度为线性匀速,同时会重复旋转动画。
controller_record = new AnimationController(
duration: const Duration(milliseconds: 15000), vsync: this);
animation_record =
new CurvedAnimation(parent: controller_record, curve: Curves.linear);
animation_record.addStatusListener((status) {
if (status == AnimationStatus.completed) {
controller_record.repeat();
} else if (status == AnimationStatus.dismissed) {
controller_record.forward();
}
});
4.下部控制器和进度条部分
播放流媒体音频使用了三方组件audioplayers
,具体代码在player_page.dart
文件内,封装了一个player组件,接受了一系列参数包括音频路径,播放操作回调等。该组件支持本地资源和网络资源,这里用网络音频资源做demo。
const Player(
{@required this.audioUrl,
@required this.onCompleted,
@required this.onError,
@required this.onNext,
@required this.onPrevious,
this.key,
this.volume: 1.0,
this.onPlaying,
this.color: Colors.white,
this.isLocal: false});
在initState方法里初始化AudioPlayer
对象。"…"是dart的级联操作符。
audioPlayer = new AudioPlayer();
audioPlayer
…completionHandler = widget.onCompleted
…errorHandler = widget.onError
…durationHandler = ((duration) {
setState(() {
this.duration = duration;
if (position != null) {
this.sliderValue = (position.inSeconds / duration.inSeconds);
}
});
})
…positionHandler = ((position) {
setState(() {
this.position = position;
if (duration != null) {
this.sliderValue = (position.inSeconds / duration.inSeconds);
}
});
});
开始播放代码
audioPlayer.play(
widget.audioUrl,
isLocal: widget.isLocal,
volume: widget.volume,
);
开始播放后,durationHandler
会回调音频总时长,positionHandler
会回调播放进度,两个回调都返回一个Duration
对象。根据这两个duration对象可以计算机播放进度的百分比,这里使用Slider
组件做进度条。
new Slider(
onChanged: (newValue) {
if (duration != null) {
int seconds = (duration.inSeconds * newValue).round();
print(“audioPlayer.seek:
$seconds”);
audioPlayer.seek(new Duration(seconds: seconds));
}
},
value: sliderValue ?? 0.0,
activeColor: widget.color,
),
总结
整体实现是非常简单的,只要对flutter的组件有所了解就能很快写出来,后面还会加入歌词滚动功能来丰富界面。
具体项目可以到 github.com/KinsomyJS/f… 查看,也欢迎star持续关注。
参考资料
- 官方文档
- pub: audioplayers
要对flutter的组件有所了解就能很快写出来,后面还会加入歌词滚动功能来丰富界面。
具体项目可以到 github.com/KinsomyJS/f… 查看,也欢迎star持续关注。
参考资料
- 官方文档
- pub: audioplayers