上面文章我们初步进行了项目搭建,下面就来开发微信项目的发现页面
自定义cell
通过微信发现页面的UI图,我们知道Cell
需要对外提供四个属性title
、subTitle
、imageName
、subImageName
用于页面展示
- 新建自定义
Cell
文件,名称为discover_cell.dart
import 'package:flutter/material.dart';
class DiscoverCell extends StatelessWidget {
final String title;
final String subTitle;
final String imageName;
final String subImageName;
DiscoverCell({
// @required表示必须要有title imageName值
@required this.title,
this.subTitle,
@required this.imageName,
this.subImageName
// 添加assert断言,进行提示
}) : assert(title != null, 'title 不能为空'), assert(imageName != null, 'imageName 不能为空');
@override
Widget build(BuildContext context) {
return Container(
// Cell添加背景色
color: Colors.white,
height: 55,
child: Row(
// 主轴是spaceBetween
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//left
Container(
padding: EdgeInsets.all(10),
child: Row(
children: [
Image(
image: AssetImage(imageName),
width: 20,
),
SizedBox(
width: 15,
),
Text(title),
],
),
),
//right
Container(
padding: EdgeInsets.all(10),
child: Row(
children: [
subTitle != null ? Text(subTitle) : Text(''),
subImageName != null
? Image(
image: AssetImage(subImageName),
width: 12,
)
: Container(),
Image( //右侧箭头
image: AssetImage('images/icon_right.png'),
width: 15,
)
],
),
),
],
),
);
}
}
发现页面完善
discover_page.dart
文件添加ListView
import 'package:flutter/material.dart';
import 'discover_cell.dart';
class DiscoverPage extends StatefulWidget {
@override
_DiscoverPageState createState() => _DiscoverPageState();
}
class _DiscoverPageState extends State<DiscoverPage> {
Color _themeColor = Color.fromRGBO(220, 220, 220, 1.0);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: _themeColor,
//以下三个是专门为了安卓使用的属性,title用于安卓退出后台顶部显示app名称
centerTitle: true,
title: Text('发现'),
elevation: 0.0, //设置NaviBar底部边栏为隐藏
),
body: Container(
color: _themeColor,
height: 800,
child: ListView(
children: <Widget>[
DiscoverCell(
imageName: 'images/朋友圈.png',
title: '朋友圈',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/扫一扫2.png',
title: '扫一扫',
),
// cell分隔线
Row(
children: <Widget>[
Container(width: 50, height: 0.5, color: Colors.white),
Container(height: 0.5, color: Colors.grey)
],
),
DiscoverCell(
imageName: 'images/摇一摇.png',
title: '摇一摇',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/看一看icon.png',
title: '看一看',
),
Row(
children: <Widget>[
Container(width: 50, height: 0.5, color: Colors.white),
Container(height: 0.5, color: Colors.grey)
],
),
DiscoverCell(
imageName: 'images/搜一搜 2.png',
title: '搜一搜',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/附近的人icon.png',
title: '附近的人',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/购物.png',
title: '购物',
subTitle: '618限时特价',
subImageName: 'images/badge.png',
),
Row(
children: <Widget>[
Container(width: 50, height: 0.5, color: Colors.white),
Container(height: 0.5, color: Colors.grey)
],
),
DiscoverCell(
imageName: 'images/游戏.png',
title: '游戏',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/小程序.png',
title: '小程序',
),
],
),
));
}
}
运行效果
cell点击切换页面
上面我们实现了发现页面的列表,但是Cell还无法点击
,下面实现Cell点击以及跳转逻辑
-
cell
添加手势GestureDetector
,添加完手势点击cell
就会有回调事件onTap
// discover_cell.dart文件中添加手势
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print('haha _$title');
},
child: Container(
// Cell添加背景色
color: Colors.white,
height: 54,
......
- 新建二级页面
discover_child_page.dart
,用于cell
跳转
import 'package:flutter/material.dart';
class DiscoverChildPage extends StatelessWidget {
final String title;
DiscoverChildPage({this.title});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('$title'),
),
body: Center(
child: Text('$title'),
),
);
}
}
- 在
GestureDetector
回调方法onTap
中添加跳转逻辑
// 导入头文件
import 'discover_child_page.dart';
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
// 添加跳转二级页面方法
Navigator.of(context).push(
// BuildContext上下文
MaterialPageRoute(builder: (BuildContext context) =>
DiscoverChildPage(title: '$title')
)
);
},
child: Container(
// Cell添加背景色
color: Colors.white,
height: 54,
......
点击跳转二级页面
注意⚠️:如果不小心点到Pub get
导致flutter卡住,一般是网络的原因
,也有可能是不小心改动了pubspec.yaml
文件,复制一份重新配置。
有状态的cell
Widget
与界面的关系
-
Widget
是界面的描述
,并不是界面。 - 如果
cell
内容非常复杂,出于性能考虑,需要把cell
部分改成有状态的
。 - 如果
cell
整体是有状态的,界面的描述会被整体改变
。 - 如果
cell
整体是有状态的,渲染的时候并不是整体渲染,而是整个cell
的Widget
会重新创建。为了提高性能,可以把cell
的部分Widget
抽取出来做成可变的
,而整个cell
是不可变的。 - 如果整个
cell
是不可变的,在创建对象的时候,cell不会重新创建,而是cell内部的Widget
会重新创建,也就是Container
会重新创建。
GestureDetector
手势的点击状态
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print('haha _$title');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context) =>
DiscoverChildPage(title: '$title')
)
);
},
// 点击
onTapDown: (TapDownDetails details) {
print('点下来了!');
},
// 取消点击
onTapCancel: () {
print('离开了!');
},
......
// 控制台成功打印
flutter: 点下来了!
flutter: 离开了!
flutter: 点下来了!
flutter: haha _DiscoverCell.title
- 修改
DiscoverCell
为有状态的
import 'package:flutter/material.dart';
import 'discover_child_page.dart';
class DiscoverCell extends StatefulWidget {
final String title;
final String subTitle;
final String imageName;
final String subImageName;
DiscoverCell({
// @required表示必须要有title imageName值
required this.title,
this.subTitle,
required this.imageName,
this.subImageName
// 添加assert断言,进行提示
}) : assert(title != null, 'title 不能为空'), assert(imageName != null, 'imageName 不能为空');
// 有状态的Widget需要实现createState方法
@override
State<StatefulWidget> createState() => _DiscoverCellState();
}
// 问题一 _DiscoverCellState访问不到DiscoverCell中的 title等属性?
// 解决方法 使用 widget.title, _DiscoverCellState中使用widget,这里的widget就是DiscoverCell
class _DiscoverCellState extends State<DiscoverCell> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print('haha _$widget.title');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context) =>
DiscoverChildPage(title: widget.title)
)
);
},
onTapDown: (TapDownDetails details) {
print('点下来了!');
},
onTapCancel: () {
print('离开了!');
},
child: Container(
// Cell添加背景色
color: Colors.white,
height: 54,
child: Row(
// 主轴是spaceBetween
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//left
Container(
padding: EdgeInsets.all(10),
child: Row(
children: [
Image(
image: AssetImage(widget.imageName),
width: 20,
),
SizedBox(
width: 15,
),
Text(widget.title),
],
),
),
//right
Container(
padding: EdgeInsets.all(10),
child: Row(
children: [
widget.subTitle != null ? Text(widget.subTitle) : Text(''),
widget.subImageName != null
? Image(
image: AssetImage(widget.subImageName),
width: 12,
)
: Container(),
Image( //右侧箭头
image: AssetImage('images/icon_right.png'),
width: 15,
)
],
),
),
],
),
),
);
}
}
问题: _DiscoverCellState访问不到DiscoverCell中的 title等属性?
解决方法:_DiscoverCellState
中使用widget.title
来访问DiscoverCell
中的title
属性,这里的widget
就是DiscoverCell
-
color
抽取出来,通过手势点击修改cell
背景色
class _DiscoverCellState extends State<DiscoverCell> {
Color _currentColor = Colors.white;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print('haha _$widget.title');
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context) =>
DiscoverChildPage(title: widget.title)
)
);
setState(() {
_currentColor = Colors.white;
});
},
onTapDown: (TapDownDetails details) {
print('点下来了!');
setState(() {
_currentColor = Colors.grey;
});
},
onTapCancel: () {
print('离开了!');
setState(() {
_currentColor = Colors.white;
});
},
child: Container(
// Cell添加背景色
color: _currentColor,
height: 54,
......
点击Cell时灰色,取消点击变成白色
我的页面布局
新建discover
文件夹右击 -> new -> package
,把发现相关页面放入
-
mine_page.dart
文件中编写内容 -
MediaQuery.removePadding
内属性removeTop: true,
可以去掉刘海屏顶部的默认偏移
import 'package:flutter/material.dart';
import 'discover/discover_cell.dart';
class MinePage extends StatefulWidget {
@override
_MinePageState createState() => _MinePageState();
}
class _MinePageState extends State<MinePage> {
Widget headerWidget() {
return Container(
height: 200,
color: Colors.red,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Color.fromRGBO(220, 220, 220, 1),
child: Stack(
children: [
//列表,用Container包一层会更灵活一点,方便抽出来
Container(
//Flutter官方封装的一些属性!!
child: MediaQuery.removePadding(
// 去掉刘海屏顶部的偏移部分
removeTop: true,
context: context,
child: ListView(
children: [
//头部
headerWidget(),
//list
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/微信 支付.png',
title: '支付',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/微信收藏.png',
title: '收藏',
),
Row(
children: <Widget>[
Container(
width: 50, height: 0.5, color: Colors.white),
Container(height: 0.5, color: Colors.grey)
],
), //分割线
DiscoverCell(
imageName: 'images/微信相册.png',
title: '相册',
),
Row(
children: <Widget>[
Container(
width: 50, height: 0.5, color: Colors.white),
Container(height: 0.5, color: Colors.grey)
],
), //分割线
DiscoverCell(
imageName: 'images/微信卡包.png',
title: '卡包',
),
Row(
children: <Widget>[
Container(
width: 50, height: 0.5, color: Colors.white),
Container(height: 0.5, color: Colors.grey)
],
), //分割线
DiscoverCell(
imageName: 'images/微信表情.png',
title: '表情',
),
SizedBox(
height: 10,
),
DiscoverCell(
imageName: 'images/微信设置.png',
title: '设置',
),
],
)
),
),
//相机 --也可以尝试用Positioned实现
Container(
// 可以专门抽出一个文件配置这些 颜色 margin 等变量,color: Colors.red, Top Margin 40
margin: EdgeInsets.only(top: 40, right: 15),
height: 25,
child: Row(
mainAxisAlignment: MainAxisAlignment.end, //主轴方向在右侧
children: [
Image(image: AssetImage('images/相机.png')),
],
),
),
],//
),
),
);
}
}
运行效果
我的页面头部
我的页面头部,自定义小部件headerWidget
开发
- 获取屏幕宽度
MediaQuery.of(context).size.width
Widget headerWidget() {
return Container(
height: 200,
color: Colors.white,
child: Container(
child: Container(
margin: EdgeInsets.only(top: 100, bottom: 20, left: 20, right: 10),
// color: Colors.red,
child: Row(
children: [
//头像
Container(
width: 70,
height: 70,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(12),
image: DecorationImage(
image: AssetImage('images/Hank.png'),
fit: BoxFit.cover)),
),
//右边的部分,包一个Expanded,懒得算了。
Expanded(
child: Container(
// color: Colors.red,
// margin:
// EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 5),
// width: MediaQuery.of(context).size.width - 100,
padding: EdgeInsets.only(left: 10, top: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 35,
child: Text(
'HK',
style: TextStyle(fontSize: 25, color: Colors.black),
),
), //昵称
Container(
height: 35,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'微信号:12334',
style: TextStyle(fontSize: 17, color: Colors.grey),
),
Image(
image: AssetImage('images/icon_right.png'),
width: 15,
)
],
),
), //微信号+箭头
],
),
)),
],
),
),
),
);
}
运行效果
网友评论