一、老套路,先看样式
左起图一是我业务中的样式,左起图二、三是下方源码展示样式(复制可直接运行,无额外组件引入)
二、讲解
1.结构拆分
我们先看下页面布局结构,首先肯定是有个GridView滚动组件来容纳内容
其次顶部有个日期的选择,点击后底部弹出下拉选择,可以选择不同年份
年份选择后,进行内容刷新,数据重新加载
每个图片底部有个一定高度的遮罩层,用来放一些文字
2.看看这个布局的主内容
body里面的列表内容
右上角点击后调用了bottomModal组件
代码语言:javascript复制 @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('备忘录' _dropValue),
centerTitle: true,
elevation: 0.0,
actions: <Widget>[
IconButton(
icon: Icon(Icons.date_range),
tooltip: "编辑",
onPressed: () {
return bottomModal();
},
),
],
), //这个是顶部tab样式,如果不需要可以去掉
body: monthList());
}
3.底部弹框其实就是个showModalBottomSheet组件
isDismissible:false //点击空白区域不可关闭
row:底部的三个样式进行mainAxisAlignment: MainAxisAlignment.spaceBetween的布局排列
InkWell:为每个图标增加个点击事件
由于底部弹框也相当于一个页面,所以想要里面的select选择后内容跟着变动,就需要重定义setState()
4.核心内容列表就是一个GridView
一行显示4个
代码语言:javascript复制crossAxisCount: 4
左右间距
代码语言:javascript复制crossAxisSpacing: 10
上下间距
代码语言:javascript复制mainAxisSpacing: 10
宽高比
代码语言:javascript复制childAspectRatio: 0.6
代码语言:javascript复制 return Padding(
padding: const EdgeInsets.all(10.0),
child: SafeArea(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 0.6),
itemBuilder: (context, index) {
return _itemGrid(index);
},
itemCount: _list.length,
),
),
);
5.主要是遮罩层的讲解
这里是一个stack,通过两个组件的堆叠实现,外层要设一个颜色透明度
属性要设置自动撑满,这样组件的遮罩层才会自动撑满父组件宽度
代码语言:javascript复制fit: StackFit.expand
然后要设置一个颜色透明度
代码语言:javascript复制decoration: BoxDecoration(color: Color(0x72000000)),
以下是flutter的所有颜色透明
比如完全不透明:0xFF000000 需要将第3第4两个字母,替换为下方列表的右侧两个字符即可
代码语言:javascript复制00%=FF(不透明)
5%=F2
10%=E5
15%=D8
20%=CC
25%=BF
30%=B2
35%=A5
40%=99
45%=8c
50%=7F
55%=72
60%=66
65%=59
70%=4c
75%=3F
80%=33
85%=21
90%=19
95%=0c
100%=00(全透明)
三、源码(可直接运行调试)
代码语言:javascript复制import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Mytest extends StatefulWidget {
@override
_MytestState createState() => _MytestState();
}
class _MytestState extends State<Mytest> {
var _dropValue = '2020';
List _list = [
{
'id': '1',
'num': '0',
'cover':
'https://daybili.oss-cn-beijing.aliyuncs.com/image/202008/1m.jpg',
'name': '1月'
}
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('备忘录' _dropValue),
centerTitle: true,
elevation: 0.0,
actions: <Widget>[
IconButton(
icon: Icon(Icons.date_range),
tooltip: "编辑",
onPressed: () {
return bottomModal();
},
),
],
), //这个是顶部tab样式,如果不需要可以去掉
body: monthList());
}
//核心的内容列表数据
Widget monthList() {
return Padding(
padding: const EdgeInsets.all(10.0),
child: SafeArea(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 0.6),
itemBuilder: (context, index) {
return _itemGrid(index);
},
itemCount: _list.length,
),
),
);
}
Widget _itemGrid(index) {
return InkWell(
child: Container(
color: Colors.black,
height: 120,
padding: EdgeInsets.all(0),
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
height: 150,
child: Image.network(
_list[index]['cover'],
fit: BoxFit.fill,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
child: RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: <InlineSpan>[
TextSpan(
text: _list[index]['name'],
style: TextStyle(
fontSize: 11,
decoration: TextDecoration.none,
color: Colors.white),
),
TextSpan(
text: _list[index]['num'] '条',
style: TextStyle(
color: Colors.red,
fontSize: 13,
decoration: TextDecoration.none),
),
TextSpan(
text: '提醒',
style: TextStyle(
fontSize: 11,
color: Colors.white,
decoration: TextDecoration.none),
),
]),
),
decoration: BoxDecoration(color: Color(0x72000000)),
),
),
],
),
),
);
}
//底部日期选择框
Widget bottomModal() {
showModalBottomSheet(
isDismissible: false,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (context1, state) {
///这里的state就是setState
return Container(
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
onTap: () {
Navigator.of(context).pop();
},
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: Icon(Icons.close),
)),
selectYear(context1, state),
InkWell(
onTap: () {
Navigator.of(context).pop();
},
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Icon(Icons.done),
))
],
),
);
});
});
}
Widget selectYear(context1, state) {
return DropdownButtonHideUnderline(
child: DropdownButton(
iconSize: 20.0, //设置三角标icon的大小
value: _dropValue,
items: [
DropdownMenuItem(
child: Text('2020年'),
value: '2020',
),
DropdownMenuItem(child: Text('2021年'), value: '2021'),
DropdownMenuItem(child: Text('2022年'), value: '2022'),
],
onChanged: (value) {
state(() {
_dropValue = value;
});
setState(() {
_dropValue = value;
});
},
),
);
}
}