需求:写一个设置页面 包含三个栏目,栏目1,栏目2,栏目三更新提示
关键词:FutureBuilder showDialog AlertDialog SharedPreferences
一、技术细节:
001 网络请求版本号
002 动态显示更新标识
003 点击版本栏目弹窗显示更新内容
004 点击其他栏目跳转到其他页面
二、技术实现点:
001 构建异步网络请求
var _futureBuilderFuter;
void initState() {
var context = this.context;
_futureBuilderFuter = _getUpdate();
}
002 网络请求结束后加载列表
FutureBuilder(
future: _futureBuilderFuter,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
UpdateModel resultModel = snapshot.data;
}
003 列表组件展示
ListView.builder(
padding: EdgeInsets.all(0),
itemCount: _titles.length,
itemBuilder: (BuildContext context, int index) {
return _listTitleNormal(
context,
index,
_icons[index],
_titles[index],
version,
resultModel.data.lastBuild.toString(),
showSubTitle: index == 2 ? true : false);
}),
004 更新会话弹窗
Future<bool> _onWillPop() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('有新版本'),
content: Text(updateModel.data.content.toString()),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(
'残忍拒绝',
style: TextStyle(color: Theme.of(context).disabledColor),
)),
FlatButton(
onPressed: () {
Navigator.of(context).pop(false);
String url = updateModel.data.iosUrl;
// _navigateTo(context, url, '');
launch(url);
},
child: Text('去更新'))
],
),
) ??
false;
}
三、完整代码和显示场景
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:qianduoduo/models/update_model.dart';
import 'package:qianduoduo/service/http_manager.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:qianduoduo/config/service_url.dart';
import 'package:package_info/package_info.dart';
import 'package:qianduoduo/utils/platform_utils.dart';
import 'package:qianduoduo/router/fluro_convert_utils.dart';
import 'package:qianduoduo/router/application.dart';
import 'package:qianduoduo/router/routers.dart';
import 'package:fluro/fluro.dart';
import 'package:qianduoduo/provider/login_page_provider.dart';
import 'package:qianduoduo/provider/store.dart';
import 'package:umeng_analytics_push/umeng_analytics_push.dart';
import 'package:url_launcher/url_launcher.dart';
class MySettingPage extends StatefulWidget {
MySettingPage({Key key}) : super(key: key);
@override
_MySettingPageState createState() => _MySettingPageState();
}
class _MySettingPageState extends State<MySettingPage> {
var _futureBuilderFuter;
List<String> _titles = ['1', '2', '版本信息'];
var version;
UpdateModel updateModelTmp;
@override
void initState() {
var context = this.context;
_futureBuilderFuter = _getUpdate();
_getUpdate().then((value) {
updateModel = value;
});
// PackageInfo _packageInfo;
PlatformUtils.getAppPackageInfo().then((value) {
// _packageInfo = value;
version = value.version;
});
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
List<Image> _icons = [
Image.asset(
'images/my/fuwuxieyi.png',
width: 24,
height: 24,
color: Theme.of(context).primaryColor,
),
Image.asset(
'images/my/gongyue.png',
width: 24,
height: 24,
color: Theme.of(context).primaryColor,
),
Image.asset(
'images/my/version.png',
width: 24,
height: 24,
color: Theme.of(context).primaryColor,
),
];
return Container(
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size(ScreenUtil().setWidth(750), 44),
child: Container(
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(
'设置',
style: TextStyle(color: Colors.white),
),
automaticallyImplyLeading: false,
leading: IconButton(
color: Colors.white,
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Theme.of(context).primaryColor,
Theme.of(context).accentColor
],
),
),
),
),
body: FutureBuilder(
future: _futureBuilderFuter,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
UpdateModel resultModel = snapshot.data;
updateModelTmp = resultModel;
return Container(
width: ScreenUtil().setWidth(750),
height: ScreenUtil().setHeight(1330),
color: Theme.of(context).scaffoldBackgroundColor,
child: Stack(
children: <Widget>[
ListView.builder(
padding: EdgeInsets.all(0),
itemCount: _titles.length,
itemBuilder: (BuildContext context, int index) {
return _listTitleNormal(
context,
index,
_icons[index],
_titles[index],
version,
resultModel.data.lastBuild.toString(),
showSubTitle: index == 2 ? true : false);
}),
Container(
height: ScreenUtil().setHeight(70),
margin: EdgeInsets.only(
left: 30,
right: 30,
top: ScreenUtil().setHeight(700)),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Theme.of(context).primaryColor,
Theme.of(context).accentColor
],
),
borderRadius: BorderRadius.circular(35),
),
child: FlatButton(
minWidth: ScreenUtil().setWidth(600),
height: ScreenUtil().setHeight(100),
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: new Text(''),
content: new Text(
'确定退出?',
style: Theme.of(context)
.textTheme
.bodyText2,
),
actions: <Widget>[
CupertinoDialogAction(
child: Text(
'取消',
style: Theme.of(context)
.textTheme
.bodyText2,
),
onPressed: () {
Navigator.of(context).pop();
},
),
CupertinoDialogAction(
child: Text(
'退出',
style: TextStyle(
color: Theme.of(context)
.primaryColor),
),
onPressed: () {
},
),
],
);
});
},
child: Text('退出登录',
style: TextStyle(color: Colors.white))),
)
],
));
} else {
return Container();
}
},
),
),
);
}
//
Widget _listTitleNormal(BuildContext context, int index, Image image,
String title, String version, String lastBuild,
{bool showSubTitle}) {
return Container(
padding: EdgeInsets.only(left: 8, right: 8),
height: ScreenUtil().setHeight(110),
alignment: Alignment.center,
child: Container(
color: Theme.of(context).cardColor,
child: Column(
children: <Widget>[
Expanded(
flex: 1,
child: ListTile(
title: Container(
child: Row(
children: <Widget>[
Container(
width: ScreenUtil().setWidth(50),
child: image,
),
Container(
padding: EdgeInsets.only(left: 12),
child: Text(
title,
style: TextStyle(
color: Theme.of(context)
.textTheme
.bodyText2
.color),
textAlign: TextAlign.left,
),
),
],
),
),
trailing: Container(
alignment: Alignment.centerRight,
width: index == 2 ? 150 : 80,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
!showSubTitle ? Container() : buildNewContainer(lastBuild),
!showSubTitle
? Container()
: Container(
child: Text(
' v' + version,
style: TextStyle(
color: Colors.grey, fontSize: 13),
),
),
Icon(
CupertinoIcons.right_chevron,
size: 20,
color: Theme.of(context).textTheme.caption.color,
),
],
),
),
onTap: () async {
print('点击了 $index 行,名称:$title');
switch (index) {
case 0:
String url =
"";
_navigateTo(context, url, _titles[index - 0]);
break;
case 1:
String url =
"";
_navigateTo(context, url, _titles[index - 1]);
break;
case 2:
_onWillPop();
break;
}
},
)),
],
),
),
);
}
Future<bool> _onWillPop() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('有新版本'),
content: Text(updateModelTmp.data.content.toString()),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(
'残忍拒绝',
style: TextStyle(color: Theme.of(context).disabledColor),
)),
FlatButton(
onPressed: () {
Navigator.of(context).pop(false);
String url = updateModelTmp.data.iosUrl;
// _navigateTo(context, url, '');
launch(url);
},
child: Text('去更新'))
],
),
) ??
false;
}
/*
判断是否有更新标志
*/
_getUpdateFlag(String lastBuild) {
var lastBuildInt = int.parse(lastBuild);
var versionValue = version.replaceAll('.', '');
var versionInt = int.parse(versionValue);
if (lastBuildInt > versionInt) {
return true;
}
return false;
}
/*
构建更新标记控件
*/
buildNewContainer(String lastBuild) {
bool updateFlag = _getUpdateFlag(lastBuild);
return !updateFlag
? Container()
: Container(
decoration: new BoxDecoration(
border: new Border.all(color: Colors.redAccent, width: 1.0),
borderRadius: new BorderRadius.circular((4.0)),
),
width: 40.0,
height: 20.0,
alignment: Alignment.center,
child: Text(
'New',
style: TextStyle(color: Colors.redAccent, fontSize: 13),
),
);
}
Future _getUpdate() async {
ResultModel resultModel = await HTTPManager.requestBase(
ServiceUrl.checkversion, {"build": '0'}, null, null);
UpdateModel updateModel = UpdateModel.fromJson(resultModel.data);
return updateModel;
}
setPreferences(String key, String value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(key, value);
}
Future<String> _getPreferences(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String value = prefs.getString(key);
return value;
}
removePreferences(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(key);
}
void _navigateTo(BuildContext context, String url, String title) {
url = FluroConvertUtils.fluroCnParamsEncode(url);
title = FluroConvertUtils.fluroCnParamsEncode(title); //fluro 不支持中文需要转换下
Application.router.navigateTo(
context, '${QDDRouters.webviewPage}?url=$url&title=$title',
transition: TransitionType.cupertino);
}
}