封装带文字的小图标
smallIconText(IconData iconData, var text) {
var style = TextStyle(fontSize: 12, color: Colors.grey);
if (text is int) {
text = countFormat(text);
}
return [
Icon(iconData, color: Colors.grey, size: 12,),
Text('$text', style: style,)
]
}
带动画的展开列表组件
expandable_content.dart
// 可展开的 Widget
class ExpandbleContent extends StatefulWidget {
final VideoMo mo;
const ExpandbleContent({Key key, this.mo}) : super(key: key);
@override
_ExpandbleContentState createState() => _ExpandbleContentState();
}
class _ExpandbleContentState extends State<ExpandbleContent>
with TickerProviderStateMixin {
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
// 是否展开
bool _expand = false;
// 用来管理 Animation
AnimationController _controller;
// 生成动画高度的值
Animation<double> _heightFactor;
@override
void initState() {
super.initState();
_controller =
AnimationController(duration: Duration(milliseconds: 200), vsync: this);
_heightFactor = _controller.drive(_easeInTween);
_controller.addListener(() {
// 监听动画值的变化
print(_heightFactor.value);
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 15, right: 15, top: 5),
child: Column(
children: [
_buildTitle(),
Padding(padding: EdgeInsets.only(bottom: 8)),
_buildInfo(),
_buildDes()
],
),
);
}
_buildTitle() {
return InkWell(
onTap: _toggleExpand,
child: Row(
// 主轴两端对齐
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// 交叉轴左对齐
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Expanded: 获得最大宽度,以便显示省略号
Expanded(
child: Text(widget.mo.title,
maxLines: 1, overflow: TextOverflow.ellipsis)),
Padding(padding: EdgeInsets.only(left: 15)),
Icon(
_expand
? Icons.keyboard_arrow_up_sharp
: Icons.keyboard_arrow_down_sharp,
color: Colors.grey,
size: 16,
)
],
),
);
}
void _toggleExpand() {
setState(() {
_expand = !_expand;
if (_expand) {
// 执行动画
_controller.forward();
} else {
// 反向执行动画
_controller.reverse();
}
});
}
_buildInfo() {
var style = TextStyle(fontSize: 12, color: Colors.grey);
var dateStr = widget.mo.createTime.length > 10
? widget.mo.createTime.substring(5, 10)
: widget.mo.createTime;
return Row(
children: [
...smallIconText(Icons.ondemand_video, widget.mo.view),
Padding(padding: EdgeInsets.only(left: 10)),
...smallIconText(Icons.ondemand_video, widget.mo.view),
Text(
' $dateStr',
style: style,
)
],
);
}
_buildDes() {
var child = _expand
? Text(widget.mo.desc,
style: TextStyle(fontSize: 12, color: Colors.grey))
: null;
return AnimatedBuilder(
animation: _controller.view,
builder: (BuildContext context, Widget child) {
return Align(
heightFactor: _heightFactor.value,
// fix 从布局之上的位置开始展开
alignment: Alignment.topCenter,
child: Container(
// 撑满宽度后,让内容对齐
alignment: Alignment.topLeft,
padding: EdgeInsets.only(top: 8),
child: child,
),
);
});
}
}