前幾天在QQ群里看到有人問(wèn)類(lèi)似這種頭像堆疊的效果在Flutter里面怎么實(shí)現(xiàn)?

image.png
想了一想,在Flutter里面好像可以用Stack和Positioned來(lái)實(shí)現(xiàn)。
最后效果如下

image.png
問(wèn)題1:Stack靠右不好處理,現(xiàn)在是用 Row 嵌套2個(gè) Expanded(黃色背景和紅色背景),然后根據(jù)顯示頭像的數(shù)量來(lái)計(jì)算這2個(gè)Expanded的 flex。
問(wèn)題2:動(dòng)態(tài)調(diào)整Stack里面頭像的數(shù)量。第一行,靠左顯示可以很好的解決。第二行,靠右顯示,因?yàn)镾tack被Expanded包圍,如果用函數(shù)返回一個(gè) List<Widget>給Stack的children,F(xiàn)lutter會(huì)報(bào)錯(cuò)。

image.png
PS: 問(wèn)題1,2的解決。使用SizedBox

image.png
Container(
height: 40,
alignment: Alignment.topRight,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(
width: _getImageStackWidth(8),
height: double.infinity,
child: Stack(
children: _getStackItems(8),
),
),
Icon(Icons.arrow_forward),
],
)),
最后上代碼
import 'package:flutter/material.dart';
class ImageStackPage extends StatelessWidget {
final double sizeW = 50.0;
final double offsetW = 20.0;
int _getSpaceStackFlex(BuildContext context, int imageNumber) {
int maxNum = (MediaQuery.of(context).size.width - 16).toInt();
int num = (offsetW * (imageNumber - 1) + sizeW).toInt();
return maxNum - num + 1;
}
int _getImageStackFlex(BuildContext context, int imageNumber) {
int num = (offsetW * (imageNumber - 1) + sizeW).toInt();
return num;
}
double _getImageStackWidth(int imageNumber) {
return offsetW * (imageNumber - 1) + sizeW;
}
List<Widget> _getStackItems(int count) {
List<Widget> _list = new List<Widget>();
for (var i = 0; i < count; i++) {
double off = 20.0 * i;
_list.add(Positioned(
left: off,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head02.png"),
width: sizeW,
height: sizeW,
),
),
));
}
return _list;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('頭像堆疊'),
),
body: Container(
child: Column(
children: <Widget>[
Container(
height: 40,
alignment: Alignment.topRight,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(
width: _getImageStackWidth(8),
height: double.infinity,
child: Stack(
children: _getStackItems(8),
),
),
Icon(Icons.arrow_forward),
],
)),
Container(
height: 40,
child: Container(
color: Colors.teal,
child: Stack(
children: _getStackItems(8),
),
)),
Container(
color: Colors.grey,
child: new Row(
children: <Widget>[
Expanded(
flex: _getSpaceStackFlex(context, 8),
child: Container(
color: Colors.yellow,
height: 40,
),
),
Expanded(
flex: _getImageStackFlex(context, 8),
child: Container(
color: Colors.red,
child: Stack(
alignment: AlignmentDirectional.bottomEnd,
children: <Widget>[
CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
Positioned(
right: 20,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head02.png"),
width: sizeW,
height: sizeW,
),
),
),
Positioned(
right: 40,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
),
Positioned(
right: 60,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
),
Positioned(
right: 80,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
),
Positioned(
right: 100,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
),
Positioned(
right: 120,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
),
Positioned(
right: 140,
child: CircleAvatar(
child: Image(
image: AssetImage("images/head01.png"),
width: sizeW,
height: sizeW,
),
),
)
],
),
),
),
Icon(Icons.arrow_forward),
],
)),
],
),
),
);
}
}