登录头像处理:
接着上一次https://www.cnblogs.com/webor2006/p/13028104.html的功能继续往下撸,在上一次中已经处理了登录的接口回调了,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/a0b906e569edec56ce761515828d07e0.png)
接下来则需要请求用户信息接口了,瞅一下官网:
![](https://i-blog.csdnimg.cn/blog_migrate/ab24b13b569cd599ef534b86131884b1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/41d60577d92af08f082c54a40cb73bd0.png)
先来定义一下URL:
![](https://i-blog.csdnimg.cn/blog_migrate/f06ea1c1de69307370a5cce3e80de4ca.png)
接下来调用一下:
![](https://i-blog.csdnimg.cn/blog_migrate/f7922fe6c54b26948de482fcef1284ab.png)
下面请求看一下能否成功?
![](https://i-blog.csdnimg.cn/blog_migrate/26779a5606dfb0595ef896b41e9107bd.png)
没问题,接下来则来处理结果,并显示头像和用户名:
![](https://i-blog.csdnimg.cn/blog_migrate/9f437590606cc4ec4ce7b31ff424eb19.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b886116eebe73b337c9322034368d986.png)
好,接下来则来做一下界面刷新,一个是用户头像,另一个是用户名称,这块逻辑就比较简单了,加判断如下:
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context, index) {
if (index == 0) {
//用户头像
return Container(
color: Color(AppColors.APP_THEME),
height: 150.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: userAvatar != null
? Container(//网络加载图像
width: 60.0,
height: 60.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 2.0,
),
image: DecorationImage(
image: NetworkImage(userAvatar),
fit: BoxFit.cover,
)),
)
: Container(//默认加载图像
width: 60.0,
height: 60.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 2.0,
),
image: DecorationImage(
image: AssetImage(
'assets/images/ic_avatar_default.png'),
fit: BoxFit.cover,
)),
),
onTap: () {
_login();
},
),
SizedBox(
//加间距
height: 10.0,
),
Text(
'点击头像登录',
style: TextStyle(color: Colors.white),
)
],
),
),
);
}
index -= 1;
return ListTile(
leading: Icon(menuIcons[index]), //左图标
title: Text(menuTitles[index]), //中间标题
trailing: Icon(Icons.arrow_forward_ios),
);
},
separatorBuilder: (context, index) {
return Divider();
}, //分隔线
itemCount: menuTitles.length + 1);
}
此时运行看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/aa8428f2b45546636ee7cc6ce713fce1.png)
不过这里有一个代码有问题,就是关于默认头像这块,什么问题呢?先来看一下默认的头像长啥样?
![](https://i-blog.csdnimg.cn/blog_migrate/0d0fc6cc976ad28271f4688c82bcb342.png)
本身就是带白边框的,但是我们代码中又画蛇添足了一下:
![](https://i-blog.csdnimg.cn/blog_migrate/e0ac9aeae894be048426384ddb72700f.png)
所以咱们可以简化一下,直接用AssetImage来显示既可:
![](https://i-blog.csdnimg.cn/blog_migrate/1aae8d06faf599f72af856c5a977b08c.png)
好,接下来再来处理用户名,比较简单,改一句代码既可:
![](https://i-blog.csdnimg.cn/blog_migrate/d22e18a92614ac3f86effadc0ce6e81d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/35197851df966c9650b31ac55ed8239a.png)
复习一下:https://www.cnblogs.com/webor2006/p/11975291.html,
![](https://i-blog.csdnimg.cn/blog_migrate/d0b7304a6973d4d63ab2d641b2c2911c.png)
运行:
![](https://i-blog.csdnimg.cn/blog_migrate/329f1b3047b3b6deedbe1de57e87579c.png)
接下来再来完善一下代码,进这个界面时则需要主动查一下是否已经有当前用户的信息了,有则需要显示到界面上,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6de5f25f4a3b33d5d70f8c9b182ad0ed.png)
![](https://i-blog.csdnimg.cn/blog_migrate/55d578c7320adbbf78f3f2a7c6a8c52f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/28325c546bf572c2dce37323f8fc9958.png)
// 用户基本信息
class User {
String gender;
String name;
String location;
int id;
String avatar;
String email;
String url;
User(
{this.gender,
this.name,
this.location,
this.id,
this.avatar,
this.email,
this.url});
}
接下来看一下整体的效果:
![](https://i-blog.csdnimg.cn/blog_migrate/a4714fcf98d1e0ad8a25e21be56e02ab.gif)
登出处理:
接下来再做登出处理,简单弄一个页面既可,如下:
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/common/event_bus.dart';
import 'package:flutter_osc_client/constants/constants.dart' show AppColors;
import 'package:flutter_osc_client/utils/data_utils.dart';
class SettingsPage extends StatefulWidget {
@override
_SettingsPageState createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text(
'设置',
style: TextStyle(color: Color(AppColors.APPBAR)),
),
iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
),
body: Center(
child: FlatButton(
onPressed: () {
//退出登录
DataUtils.clearLoginInfo().then((_) {
eventBus.fire(LogoutEvent());//发出退出消息
Navigator.of(context).pop();
});
},
child: Text(
'退出登录',
style: TextStyle(fontSize: 25.0),
)),
),
);
}
}
其实也就是这个点设置跳转的页面做的退出登录处理:
![](https://i-blog.csdnimg.cn/blog_migrate/a82edfc08c8ce3ee8a14acca75d1f9ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7c91162772e2ef5f30f02b262ce2d527.png)
此时再来处理一下登出的消息,很简单,直接再刷新一下界面既可:
![](https://i-blog.csdnimg.cn/blog_migrate/28acd0be0e1acc29b7da5132ad073ae6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f3234692ea66f4a45b570263bdd3cd5e.png)
此时运行瞅一下效果:
![](https://i-blog.csdnimg.cn/blog_migrate/55aec342a4192b65304d8449a5e51543.gif)
我的详情:
接下来则来处理点击头像来查看用户的详细信息,这里点击肯定得要判断登录状态了,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/517f9c5c5b6a85960253bfd238d4dfdf.png)
接下来则新建用户详情页面:
![](https://i-blog.csdnimg.cn/blog_migrate/d2a530a9c5fa4346f4c646bd4f20378c.png)
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/constants/constants.dart';
class ProfileDetailPage extends StatefulWidget {
@override
_ProfileDetailPageState createState() => _ProfileDetailPageState();
}
class _ProfileDetailPageState extends State<ProfileDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'用户详情',
style: TextStyle(color: Color(AppColors.APPBAR)),
),
iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
),
body: Column(),
);
}
}
然后链上这个页面:
![](https://i-blog.csdnimg.cn/blog_migrate/29a944a8972aebbb6946c1ead3ec681a.png)
运行看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/d9dc9b60bb7ef167901931aeb84a897b.gif)
接下来则来集中实现一下用户详情页面,先来看一下它长啥样:
![](https://i-blog.csdnimg.cn/blog_migrate/674c186806537b0044fac4f87e19ce87.png)
下面则来一行行构建布局,首先构建个头像,这里会用到一个新的Widget:
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/constants/constants.dart';
class ProfileDetailPage extends StatefulWidget {
@override
_ProfileDetailPageState createState() => _ProfileDetailPageState();
}
class _ProfileDetailPageState extends State<ProfileDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'用户详情',
style: TextStyle(color: Color(AppColors.APPBAR)),
),
iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
),
body: Column(
children: <Widget>[
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding:
const EdgeInsets.only(top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'头像',
style: TextStyle(fontSize: 20.0),
),
Container(
width: 60.0,
height: 60.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 2.0,
),
image: DecorationImage(
image: NetworkImage(""),
fit: BoxFit.cover,
),
),
)
],
),
),
),
],
),
);
}
}
其中用户头像这里空着是因为得要请求一个新的接口,这里先来预览一下效果:
![](https://i-blog.csdnimg.cn/blog_migrate/a2177d928c3420f722736f42ccc3666f.gif)
其中可以看到是典型的material风格的点击效果,其中就是使用了这个新的Widget:
![](https://i-blog.csdnimg.cn/blog_migrate/7031602c4f0a09bea39c9ca7559f310b.png)
接下来则来显示一下头像,刚才也提到了需要再请求一个接口,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8a9a810033cf697e1d5c596dbdad335c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/17eccda051ad5fe48b4c1a13dd359fc5.png)
下面来请求一下,先来准备一下API:
![](https://i-blog.csdnimg.cn/blog_migrate/ad98cbf7decc0eb1f3ddfb4e84339c0f.png)
然后新建一个实体,用来接收服务器所下发的信息:
![](https://i-blog.csdnimg.cn/blog_migrate/ea3a9a19a1a0acd2b8801c797b1ea21a.png)
// 用户详细信息
class UserInfo {
int uid;
String name;
int gender;
String province;
String city;
List<dynamic> platforms;
List<dynamic> expertise;
String joinTime;
String lastLoginTime;
String portrait;
int fansCount;
int favoriteCount;
int followersCount;
Map<String, dynamic> notice;
UserInfo(
{this.uid,
this.name,
this.gender,
this.province,
this.city,
this.platforms,
this.expertise,
this.joinTime,
this.lastLoginTime,
this.portrait,
this.fansCount,
this.favoriteCount,
this.followersCount,
this.notice});
}
接下来则开始请求处理:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/constants/constants.dart';
import 'package:flutter_osc_client/models/user_info.dart';
import 'package:flutter_osc_client/utils/data_utils.dart';
import 'package:flutter_osc_client/utils/net_utils.dart';
class ProfileDetailPage extends StatefulWidget {
@override
_ProfileDetailPageState createState() => _ProfileDetailPageState();
}
class _ProfileDetailPageState extends State<ProfileDetailPage> {
UserInfo _userInfo;
_getDetailInfo() {
DataUtils.getAccessToken().then((accessToken) {
//拼装请求
Map<String, dynamic> params = Map<String, dynamic>();
params['dataType'] = 'json';
params['access_token'] = accessToken;
NetUtils.get(AppUrls.MY_INFORMATION, params).then((data) {
print('MY_INFORMATION: $data');
if (data != null && data.isNotEmpty) {
Map<String, dynamic> map = json.decode(data);
UserInfo userInfo = UserInfo();
userInfo.uid = map['uid'];
userInfo.name = map['name'];
userInfo.gender = map['gender'];
userInfo.province = map['province'];
userInfo.city = map['city'];
userInfo.platforms = map['platforms'];
userInfo.expertise = map['expertise'];
userInfo.joinTime = map['joinTime'];
userInfo.lastLoginTime = map['lastLoginTime'];
userInfo.portrait = map['portrait'];
userInfo.fansCount = map['fansCount'];
userInfo.favoriteCount = map['favoriteCount'];
userInfo.followersCount = map['followersCount'];
userInfo.notice = map['notice'];
setState(() {
_userInfo = userInfo;
});
}
});
});
}
@override
void initState() {
super.initState();
_getDetailInfo();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'用户详情',
style: TextStyle(color: Color(AppColors.APPBAR)),
),
iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
),
body: _userInfo == null
? Center(
child: CupertinoActivityIndicator(),
)
: Column(
children: <Widget>[
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'头像',
style: TextStyle(fontSize: 20.0),
),
Container(
width: 60.0,
height: 60.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 2.0,
),
image: DecorationImage(
image: NetworkImage(_userInfo.portrait),
fit: BoxFit.cover,
),
),
)
],
),
),
),
],
),
);
}
}
再运行:
![](https://i-blog.csdnimg.cn/blog_migrate/bb27bab783514fd4e1714a0e74cd9425.gif)
ok,至于其它信息条目的显示基本写法差不多,就把代码贴出来了,不一一细说了,比较多,但都比较容易理解:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'用户详情',
style: TextStyle(color: Color(AppColors.APPBAR)),
),
iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
),
body: _userInfo == null
? Center(
child: CupertinoActivityIndicator(),
)
: Column(
children: <Widget>[
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'头像',
style: TextStyle(fontSize: 20.0),
),
Container(
width: 60.0,
height: 60.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 2.0,
),
image: DecorationImage(
image: NetworkImage(_userInfo.portrait),
fit: BoxFit.cover,
),
),
)
],
),
),
),
Divider(),
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'昵称',
style: TextStyle(fontSize: 20.0),
),
Text(
_userInfo.name,
style: TextStyle(fontSize: 20.0),
),
],
),
),
),
Divider(),
Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'加入时间',
style: TextStyle(fontSize: 20.0),
),
Text(
_userInfo.joinTime,
// _userInfo.joinTime.split(' ')[0],
style: TextStyle(fontSize: 20.0),
),
],
),
),
Divider(),
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'所在地区',
style: TextStyle(fontSize: 20.0),
),
Text(
_userInfo.city,
style: TextStyle(fontSize: 20.0),
),
],
),
),
),
Divider(),
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: Text(
'开发平台',
style: TextStyle(fontSize: 20.0),
),
),
Expanded(
child: Text(
// 'Android,C/C++,J2ME/K-Java,Python,.NET/C#',
_userInfo.platforms.toString(),
style: TextStyle(fontSize: 20.0),
textAlign: TextAlign.right,
),
),
],
),
),
),
Divider(),
InkWell(
onTap: () {
//TODO
},
child: Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: Text(
'专长领域',
style: TextStyle(fontSize: 20.0),
),
),
Expanded(
child: Text(
// '手机软件开发,服务器开发,软件开发管理',
_userInfo.expertise.toString(),
style: TextStyle(fontSize: 20.0),
textAlign: TextAlign.right,
),
),
],
),
),
),
Divider(),
Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'粉丝数',
style: TextStyle(fontSize: 20.0),
),
Text(
_userInfo.fansCount.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,
),
],
),
),
Divider(),
Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'收藏数',
style: TextStyle(fontSize: 20.0),
),
Text(
_userInfo.favoriteCount.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,
),
],
),
),
Divider(),
Container(
margin: const EdgeInsets.only(left: 20.0),
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 20.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'关注数',
style: TextStyle(fontSize: 20.0),
),
Text(
_userInfo.followersCount.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,
),
],
),
),
Divider(),
],
),
);
}
关于上面的代码细节不用过多纠结,都是熟能生巧的事,练得多了自然而然也就亲切了,写得少当然感觉很懵,重点是理解,当实际自己来实现时只要有思路再到时查阅一下既可,反正我也记不住。
我的消息:
接下来则来处理这块的点击事件,不过这里仅以它为例来实现一下:
![](https://i-blog.csdnimg.cn/blog_migrate/749156444fd37960b0221079b8dd844d.png)
点击时需要判断是否登录:
![](https://i-blog.csdnimg.cn/blog_migrate/98581076bcbc4344f947d043d2187fd1.png)
然后新建一个页面:
![](https://i-blog.csdnimg.cn/blog_migrate/a30c351cc80a8b11721902ac30998fb0.png)
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/constants/constants.dart';
class MyMessagePage extends StatefulWidget {
@override
_MyMessagePageState createState() => _MyMessagePageState();
}
class _MyMessagePageState extends State<MyMessagePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text(
'消息中心',
style: TextStyle(
color: Color(AppColors.APPBAR),
),
),
iconTheme: IconThemeData(
color: Color(AppColors.APPBAR),
),
),
);
}
}
运行看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/9f8aefa565f3e8804936a715940b72dd.gif)
接下来则来构建消息中心页面,它长啥样呢?先看看:
![](https://i-blog.csdnimg.cn/blog_migrate/d0819061c1f071d8037e9793e7f825b6.gif)
关于这种Tab样式界面的写法可以参考https://www.cnblogs.com/webor2006/p/12578218.html,下面来构建一下:
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/constants/constants.dart';
class MyMessagePage extends StatefulWidget {
@override
_MyMessagePageState createState() => _MyMessagePageState();
}
class _MyMessagePageState extends State<MyMessagePage> {
List<String> _tabTitles = ['@我', '评论', '私信'];
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: _tabTitles.length,
child: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text(
'消息中心',
style: TextStyle(
color: Color(AppColors.APPBAR),
),
),
iconTheme: IconThemeData(
color: Color(AppColors.APPBAR),
),
bottom: TabBar(
tabs: _tabTitles
.map((title) => Tab(
text: title,
))
.toList()),
),
),
);
}
_buildMessageList() {}
}
运行:
![](https://i-blog.csdnimg.cn/blog_migrate/c51a8fe6170843595f94e30b137a5cfb.png)
TAB效果有了,接下来则需要构建一下TAB之后下面页面的内容:
![](https://i-blog.csdnimg.cn/blog_migrate/11a3e25c0ab09fbdf3ce39c828acd94f.png)
运行:
![](https://i-blog.csdnimg.cn/blog_migrate/b5bb1eda53cf27e3bfc193b78bd1d33e.gif)
这里只以私信为例,前面两个就占个位得了,这里私信又有一个新接口需要请求:
![](https://i-blog.csdnimg.cn/blog_migrate/9e54360e8c9b1cbd04a51015b89dc165.png)
所以新建一个URL:
![](https://i-blog.csdnimg.cn/blog_migrate/0e40e5a167c16d24e33d3893a7841e63.png)
然后咱们来请求一下它,并根据数据来构建私信列表显示:
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_osc_client/constants/constants.dart';
import 'package:flutter_osc_client/utils/data_utils.dart';
import 'package:flutter_osc_client/utils/net_utils.dart';
class MyMessagePage extends StatefulWidget {
@override
_MyMessagePageState createState() => _MyMessagePageState();
}
class _MyMessagePageState extends State<MyMessagePage> {
List<String> _tabTitles = ['@我', '评论', '私信'];
List messageList;
int curPage = 1;
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: _tabTitles.length,
child: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text(
'消息中心',
style: TextStyle(
color: Color(AppColors.APPBAR),
),
),
iconTheme: IconThemeData(
color: Color(AppColors.APPBAR),
),
bottom: TabBar(
tabs: _tabTitles
.map((title) => Tab(
text: title,
))
.toList()),
),
body: TabBarView(children: [
Center(
child: Text('暂无内容'),
),
Center(
child: Text('暂无内容'),
),
_buildMessageList(),
]),
),
);
}
_buildMessageList() {
if (messageList == null) {
//获取私信
_getMessageList();
return Center(
child: CupertinoActivityIndicator(),
);
}
return RefreshIndicator(
child: ListView.separated(
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
Image.network(messageList[index]['portrait']),
SizedBox(
width: 10.0,
),
Expanded(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'${messageList[index]['sendername']}',
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
'${messageList[index]['pubDate']}',
style: TextStyle(
fontSize: 12.0, color: Color(0xffaaaaaa)),
),
],
),
Text(
'${messageList[index]['content']}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(fontSize: 12.0),
),
],
),
),
],
),
);
},
separatorBuilder: (context, index) {
return Divider();
},
itemCount: messageList.length),
onRefresh: _pullToRefresh);
}
Future<Null> _pullToRefresh() async {
curPage = 1;
_getMessageList();
return null;
}
void _getMessageList() {
DataUtils.isLogin().then((isLogin) {
if (isLogin) {
DataUtils.getAccessToken().then((accessToken) {
print('accessToken: $accessToken');
//拼装请求
Map<String, dynamic> params = Map<String, dynamic>();
params['dataType'] = 'json';
params['page'] = curPage;
params['pageSize'] = 10;
params['access_token'] = accessToken;
NetUtils.get(AppUrls.MESSAGE_LIST, params).then((data) {
print('MY_INFORMATION: $data');
if (data != null && data.isNotEmpty) {
Map<String, dynamic> map = json.decode(data);
var _messageList = map['messageList'];
setState(() {
messageList = _messageList;
});
}
});
});
}
});
}
}
上面的代码比较多,其实都比较好理解,不多说了,直接运行看看效果:
![](https://i-blog.csdnimg.cn/blog_migrate/5bd7ece21f9e6a109fd6583d263ac854.png)
对于界面上这样的布局:
![](https://i-blog.csdnimg.cn/blog_migrate/5377c92f0f56b1342bc8ca2fb8ca01f3.png)
可以看到在Flutter中写着还是蛮麻烦的:
![](https://i-blog.csdnimg.cn/blog_migrate/7d1aa88b3b60ff18f66d5eb4ad1d66bf.png)
而且这种嵌套看着也比较头晕,只怪自己还是比较菜,慢慢来,先能跟着做出效果来,之后再慢慢熟练,这里有上拉刷新的逻辑,那分页下拉加载呢?关于这块可以参考https://www.cnblogs.com/webor2006/p/12748524.html,需要自己手动添加逻辑,这里略过了。