通过Stack + 动画
1.Stack组件可以让后面的组件覆盖在前一个上面,我们可以使用Stack来进行嵌套
2.动画部分
late Animation<double> animation;
late AnimationController controller;
AnimationStatus? animationState;
void initState() {
super.initState();
itemList = copyWithList(widget.data.map((e) => e).toList());
// 动画控制器
controller = AnimationController(
duration: const Duration(milliseconds: 100), vsync: this);
// 动画方式
animation = Tween<double>(begin: 0, end: 100).animate(controller)
..addListener(() {
setState(() {
animationValue = animation.value
});
})
..addStatusListener((AnimationStatus state) {
setState(() {
animationState = state;
});
});
}
3.stack部分
Stack(
children: [
// 撑满
Container(
height: double.infinity,
),
// 底层滚动的列表
Positioned(
top: 50,
bottom: 12,
left: 0,
right: 0,
child: SingleChildScrollView(
child:Column(
children:[
Container(
color: Colors.red,
height: 300,
width: double.infinity,
child: const Text("1111111"),
),
Container(
color: Colors.blue,
height: 300,
width: double.infinity,
child: const Text("1111111"),
),
Container(
color: Colors.green,
height: 300,
width: double.infinity,
child: const Text("1111111"),
),
]
)
)
),
// 选项栏
Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: selects.asMap().keys.map(
(e) {
return InkWell(
onTap: () {
if (selects[e]['text'] == '排序') {
itemList = itemList.reversed.toList();
}
setState(() {
index = e;
for (int i = 0; i < selects.length;
if (e == i) {
setState(() {
selects[e]['isSelect'] =
!selects[e]['isSelect'];
});
if (e == 2) {
selects[e]['isSelect']
? controller.reverse()
: controller.forward();
} else {
controller.reset();
}
} else {
setState(() {
selects[i]['isSelect'] = true;
});
}
}
});
},
child: Row(
children: [
Text(
selects[e]['text'],
style: TextStyle(
fontSize: 16,
color: index == e
? Colors.green
: Colors.black),
),
Icon(selects[e]['isSelect']
? Icons.arrow_drop_down
: Icons.arrow_drop_up),
],
),
);
},
).toList(),
),
),
Row(
children: [
TextButton(
onPressed: () {},
child: const Text(
"通知",
style: TextStyle(
color: Color(0xff0FAB6B),
fontSize: 16,
),
),
),
CupertinoSwitch(
value: isChange,
onChanged: (bool val) {
setState(() {
isChange = val;
});
},
activeColor: const Color(0xff0FAB6B),
)
],
)
],
),
),
),
// 阴影,遮罩部分
Positioned(
top: 40,
left: 0,
right: 0,
bottom: 0,
child: !selects[2]['isSelect']
? SizedBox(
child: InkWell(
child: AnimatedBuilder(
animation: animation,
builder: (context, child) {
// 这里是下拉框下方阴影 点击阴影隐藏下拉框
return Container(
width: double.infinity,
height:MediaQuery.of(context).size.height,
color: Colors.black.withOpacity(0.5),
);
},
),
onTap: () {
cancal();
},
),
)
: const SizedBox(),
),
// 弹出框
Positioned(
top: 40,
left: 0,
right: 0,
child: AnimatedBuilder(
animation: animation,
child: SingleChildScrollView(
child: Column(
children: [
InkWell(
onTap: () {
statusCount = 2;
selects[2]['text'] = '状态';
itemList = widget.data;
cancal(); // 因为这个函数中有setState,所以上面不用写
},
child: Container(
height: 30,
padding: const EdgeInsets.only(left: 30),
child: Row(
children: [
Icon(
Icons.check,
color: statusCount == 2
? Colors.red
: Colors.transparent,
),
const Text(
"全部",
style: TextStyle(
fontSize: 16,
),
),
],
),
),
),
InkWell(
onTap: () {
statusCount = 0;
selects[2]['text'] = '已停售';
itemList = widget.data
.where((element) => element['status'] == "已停售")
.toList();
cancal(); // 因为这个函数中有setState,所以上面不用写
},
child: Container(
height: 30,
padding: const EdgeInsets.only(left: 30),
child: Row(
children: [
Icon(
Icons.check,
color: statusCount == 0
? Colors.red
: Colors.transparent,
),
const Text(
"已停售",
style: TextStyle(
fontSize: 16,
),
),
],
),
),
),
InkWell(
onTap: () {
statusCount = 1;
selects[2]['text'] = '已成交';
itemList = widget.data
.where((element) => element['status'] == "已成交")
.toList();
cancal();
},
child: Container(
height: 30,
padding: const EdgeInsets.only(left: 30),
child: Row(
children: [
Icon(
Icons.check,
color: statusCount == 1
? Colors.red
: Colors.transparent,
),
const Text(
"已成交",
style: TextStyle(
fontSize: 16,
),
),
],
),
),
),
],
),
),
builder: (context, child) {
return Container(
height: animation.value,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(16),
bottomRight: Radius.circular(16),
),
color: Colors.white,
),
child: child,
);
},
),
),
],
)