- Flutter在2018年里从Beta一直走到1.0版本,虽然暴露出1.0版本仍然有不少Bug、生态不完善、库少、某些功能实现很差等问题,可是关注它的人们依然热情很高,天天都有关于Flutter的新的东西产出,说明不少人仍是很看好它的。
- 国内阿里腾讯等也在积极布道,作了不少高质量的分享。也许大火须要时间,商用也须要胆量,可是如今学习了解一下,仍是颇有必要的。
此次选择仿写一个很轻量的项目单读App
,主要经过项目来练习一下经常使用的组件
、布局
、网络请求
、json解析
等。javascript
本项目是经过Charles
抓包工具来获取项目Api
,经过Apple Configurator 2
工具来获取仿写App
的图片资源,关于两个工具的介绍和使用能够参考下之前的文章Swift高仿喜马拉雅APP之一Charles抓包、图片资源获取等php
以项目进来看到的主页面为例介绍布局:html
项目主页采用的是PageView
,当前屏幕所能看到的即时PageView
的单一页面,该页面的布局主要是使用Column
里面children: <Widget>[]
包裹各类Widget
,顶部图片是使用 new Image.network()
来获取显示网络图片,中间部分为包裹的Container、Text
,各个组件之间间距可使用Padding
或者Expanded
来零活控制,最底部选择使用Row
包裹一下喜欢喝评论按钮等。前端
主页面的主要代码示例:html5
返回PageView:java
return Center(
child: PageView.builder(
itemCount: dataList.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return calendarList(dataList[index],index,context);
},
),
);
复制代码
网络请求和数据解析:android
须要在工程的pubspec.yaml
文件中dependencies:
中引入 dio: ^1.0.13
该库为网络请求库^x.x.x
为版本号。 在dependencies:
中引入json_annotation:: ^2.0.0
,在dev_dependencies:
中引入 json_serializable: ^2.0.1
build_runner: ^1.1.2
,这三个为json解析库,配合使用就能够进行网络请求和json解析数据赋值了,引入完成后记得右上角的Packages get
一下。ios
使用举例以下:git
说明一下: 因为是抓包接口,抓包中含有加密的sign
字段并无破解,致使接口有很短的超时时间,因此该项目中使用了不少的json
本地接口数据,也意味着没有分页,可是文字模块的接口是获取的网络接口,含有分页和下拉接在更多,因此该项目能够看到本地json
数据和网络数据两种处理方式。
对于本地json
文件的引入,能够直接拖动一个json
到工程本身新建的文件夹,而后在pubspec.yaml
文件中flutter:
下面写上assets:
表明引入资源文件,而后把具体路径写下就好了例如- json/HomeData.json
不过须要注意写法和空格,一样项目中须要的图片资源也是拖进新的个文件夹内,而后在这里面作下引入Packages get
一下,具体的能够查看本项目源码。
本地
json
数据load
和解析示例:
void loadData() async{
String cssStr = await DefaultAssetBundle.of(context).loadString('json/HomeData.json');
CommonModel model = CommonModel.fromJson(json.decode(cssStr));
setState(() {
List<dynamic>data = [];
data.addAll(model.datas);
dataList.addAll(data);//给数据源赋值
});
}
复制代码
网络接口请求和解析示例: 说明一下请求http接口的时候iOS须要添加信任Http认证,具体为iOS文件夹-->Runner-->info.plist添加代码
![]()
/// 这里是请求接口数据,当滑动到最底端的时候会判断是否加载更多更改二个参数,post_id,page+1,而后把新请求的数据追加到之前的数据中
void loadData(String post_id, int curPage,bool isMore) async{
Dio dio = new Dio();
Response response = await dio.get("http://203.195.230.211/index.php?m=Home&c=Api2&a=getTagList&tag=$tag&p=$curPage&client=iOS&show_sdv=1&page_id=$post_id&create_time=0&sign=24a904d18a786327741ca5613180ceda&time=1547092560&device_id=A39632E7-F689-405B-A3A3-0319D6095B54&version=1.6.2&client=iOS");
CommonModel result = CommonModel.fromJson(response.data);
setState(() {
if(!isMore) {
List<dynamic>data = [];
data.addAll(result.datas);
new_page_id = result.datas[data.length-1].id;
dataList.addAll(data);//给数据源赋值
}else{
List<dynamic>data = [];
data.addAll(result.datas);
new_page_id = result.datas[data.length-1].id;
dataList.addAll(data);
}
});
}
}
复制代码
对于数据模型的建立:
这里利用一个工具来自动生成model
,json2dart, 如图所示:
具体用法是先在工程中建立一个例如HomeDataModel.dart
文件,而后利用该工具生成json
格式,拷贝到该文件下面,注意上图中的entity
应该改成HomeDataModel
,这个时候终端cd到该项目的根目录,便是ls
能够看到pubspec.yaml
的目录,运行flutter packages pub run build_runner build
,过一会会自动生成HomeDataModel.g.dart
的文件。
到这里首页部分的布局
,数据模型
,接口请求
,数据解析
都好了,就能够赋值查看真是数据的页面了,这里以主页底部Row
,即点赞喜欢部分赋值代码示例,具体的请看源码。
class _LikeWidgetState extends State<LikeWidget> {
bool _isLike = true;
void _togoLike() {
setState(() {
/// 若是是喜欢置为未喜欢
if (_isLike) {
_isLike = false;
/// 若是是未喜欢置为喜欢
} else {
_isLike = true;
}
});
}
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
new Expanded(
child:new Row(
children: <Widget>[
new IconButton(
icon: Image.asset('assets/comment@2x.png'),
onPressed: (){
Navigator.of(context).push(new MaterialPageRoute(builder: (ctx) {
return new CommentPageStateful(post_id: widget.data.id);
}));
}
),
new Text(
widget.data.comment,
style: TextStyle(
color: Colors.black,
fontSize: 16,
),
),
new IconButton(
icon: (_isLike ? new Image.asset("assets/like@2x.png") : new Image.asset("assets/liked@2x.png")),
onPressed: (){
_togoLike();
}
),
new Text(
/// 这里是先经过int.parse(widget.data.good) string转int ,而后toString()再转成string
_isLike ? int.parse(widget.data.good).toString() : (int.parse(widget.data.good)+1).toString(),
style: TextStyle(
color: Colors.black,
fontSize: 16,
),
),
],
)
),
new Container(
padding: EdgeInsets.only(right: 15),
child: new Text(
'阅读数 '+widget.data.view,
style: TextStyle(
color: Colors.black,
fontSize: 16,
),
),
)
],
);
}
}
复制代码
经过主页面能够看到,顶部AppBar
左右两边按钮能够弹出左右Drawer
,因为系统的Drawer
是不能遮罩全屏的,因此这里选择自定义Widget
实现全屏遮罩的Drawer
。
效果图:
自定义
Drawer
示例代码:
/// 自定义的左边栏抽屉
class LeftDrawer extends StatefulWidget {
final double elevation;
final Widget child;
final String semanticLabel;
final double widthPercent;
///add start
final DrawerCallback callback;
///add end
const LeftDrawer({
Key key,
this.elevation = 16.0,
this.child,
this.semanticLabel,
this.widthPercent,
///add start
this.callback,
///add end
}) : assert(widthPercent < 1.0 && widthPercent > 0.0),
super(key: key);
@override
_LeftDrawerState createState() => _LeftDrawerState();
}
class _LeftDrawerState extends State<LeftDrawer> {
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context));
String label = widget.semanticLabel;
final double _width = MediaQuery.of(context).size.width * widget.widthPercent;
return Semantics(
scopesRoute: true,
namesRoute: true,
explicitChildNodes: true,
label: label,
child: ConstrainedBox(
constraints: BoxConstraints.expand(width: _width),
child: Material(
color: Colors.black87,
elevation: widget.elevation,
child: Container(
),
),
),
);
}
复制代码
对于左右Drawer
中的文字按钮有个放大显示的动画,该字体动画使用的是 animated_text_kit: ^1.2.0
,有好几种动画,具体能够参考源码,具体使用为导入import 'package:animated_text_kit/animated_text_kit.dart';
Widget _AnimatedText(String str){
return SizedBox(
child: ScaleAnimatedTextKit(
duration: Duration(milliseconds: 4000),
isRepeatingAnimation: false,
text:[str],
textStyle: TextStyle(
fontSize: 35,
color: Colors.white
),
),
);
}
复制代码
Flutter
中使用WebView
,能够选择使用flutter_webview_plugin: ^0.3.0+2
插件,使用也很简单引入头文件import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'
;
Widget _WebView(String url) {
return WebviewScaffold(url: url);
}
复制代码
使用该插件能够显示通常WebView
页面,可是我工程中的WebView
页面顶部AppBar
,上面仍是有按钮的,以下图所示,点击按钮要跳转到评论界面,可是使用该插件由于返回的WebviewScaffold
,因此当在WebView
页面跳转其余页面的时候,该页面会一直在其余页面的最上层,虽然可使用widget.flutterWebviewPlugin.close();
来进行关闭该页面,可是意味着返回来的时候就看不到WebView
页面内容了,我本想去做者github
寻求答案,看到有人已经提了issue
可是做者给的标签是待解决。有人知道这个问题怎么解决请赐教。
WebView
页面,再也不进行二次跳转的状况下,还可使用
url_launcher: ^4.0.1
插件,该插件为系统插件不只能够显示
WebView
页面具体使用请自行查阅资料,使用后的页面样式是固定的,具体使用参考以下引
入import 'package:url_launcher/url_launcher.dart';
void _launchURL(String url, BuildContext context) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
onTap: (){
_launchURL(data.html5, context);
},
复制代码
url_launcher
显示的WebView
页面样式:
说明一下:
本项目中两种加载WebView
页面的方式均有使用,文字模块的二级页面的Detail
页面使用的是flutter_webview_plugin
,其他详情页面使用的均是url_launcher
显示的WebView
页面。
***追加说明:
通过群友提示发现了更好的一种webview
加载方式,使用 webview_flutter: ^0.2.0
插件,目前该项目中WebView
页面已经所有换成该方法,使用该插件能够自定义AppBar
,而且跳转页面也不会有问题,以上两种webview
加载方法能够自行选择。
具体使用为在pubspec.yaml
中引入webview_flutter: ^0.2.0
而且Packages get
一下,在须要用到的页面import 'package:webview_flutter/webview_flutter.dart';
import 'dart:async';
须要特别注意的是iOS端须要在info.plist中添加设置
class WebViewExample extends StatelessWidget {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView example'),
),
body: WebView(
initialUrl: 'https://www.baidu.com',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
),
);
}
}
复制代码
对于刚刚的使用flutter_webview_plugin
的WebView
页面右上角点击评论按钮,便可跳转评论页面,评论页面由于须要显示HeaderView
,因此选择了sticky_headers: ^0.1.7
库,使用起来效果很好也很方便,对于布局和详细代码请查看源码,sticky_headers
主要代码示例以下:
child: ListView.builder(
itemCount: newsList.length+hotsList.length+1,
itemBuilder: (context, index) {
if (index == 0) {
return StickyHeader(header: CommentHeader('喜欢', diggList.length, index),
content: DiggList(diggList, diggList.length, context),
);
}else if (hotsList.length >0 && index < hotsList.length+1) {
return StickyHeader(header: CommentHeader('最热评论', hotsList.length, index-1),
content: HotsList(hotsList[index-1], index, context),
);
}else {
return StickyHeader(header: CommentHeader('最新评论', newsList.length, index-hotsList.length-1),
content: NewsList(newsList[index-hotsList.length-1], index, context),
);
}
},
),
复制代码
评论页面效果图:
谈论页面顶部含有一个TabBar,左右滑动能够切换单读问页面和读者论页面。
代码示例以下:
class TalkStateful extends StatefulWidget {
@override
_TalkPageState createState() => new _TalkPageState();
}
class _TalkPageState extends State<TalkStateful> with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
// TODO: implement initState
super.initState();
_tabController = new TabController(vsync: this, initialIndex: 0, length: 2);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black87,
title: new Text('谈论', style: TextStyle(color: Colors.white,fontSize: 24),),
bottom: new TabBar(
isScrollable: false,//是否可滑动
unselectedLabelColor: Colors.white,//未选中按钮颜色
labelColor: Colors.white,//选中按钮颜色
labelStyle: TextStyle(fontSize: 16),//文字样式
indicatorSize: TabBarIndicatorSize.label,//滑动的宽度是根据内容来适应,仍是与整块那么大(label表示根据内容来适应)
indicatorWeight: 2.0,//滑块高度
indicatorColor: Colors.black87,//滑动颜色
indicatorPadding: EdgeInsets.only(bottom: 1),//与底部距离为1
controller: _tabController,
tabs: <Widget> [
new Tab(
text: '单读问',
),
new Tab(
text: '读者论',
)
]
),
),
body: new TabBarView(
controller: _tabController,
children: <Widget> [
new DanDuWenPage(),
new DuZheLunPage(),
]
),
);
}
}
复制代码
谈论页面效果图以下:
关于本项目就介绍到这里吧,想了解更多请看源码部分,若是有什么不懂得或者疑问能够相互交流。
iOS设置工程主文件夹例:flutter_dandu--> ios-->Runner-->Assets.xcassets-->AppIcon And LaunchImage
Android设置工程主文件夹例:flutter_dandu-->android-->app-->src--main-->res
刚接触Flutter
使用Dart
语言,确定是会别扭的,嵌套过多阅读困难,可是了解以后发现也还行,整体来讲如今谈Flutter
的未来还有点早,可是前景仍是很不错的,有时间的或者客户端前端从业者能够考虑入门学习一下。熟练以后写东西确实很快,跨平台是大势所趋,就算不是Flutter
也会有其余的出现。最重要的是Flutter
是Google
手机设备新系统Fuchsia
的UI
框架和过渡性产品,应该仍是挺看好的。
对于大佬确定是啃源码和官方文档了,可是对于小菜鸡来讲仍是找找译文和其余大佬教程吧。这里整理了一些不错的学习资源连接:
系列基础知识教程:
一、Flutter中文网:https://flutterchina.club
二、技术胖:Flutter基础视频免费教程
大佬技术文章:
1.juejin.im/user/59be05…
2.juejin.im/post/5c1f35…
3.juejin.im/user/5ad016…
4.juejin.im/post/5bc450…
5.www.jianshu.com/u/5c5872cc9…
Flutter圈子和标签及知乎:
Flutter圈子:https://www.jianshu.com/c/ebc9d2e84214
Flutter标签:https://juejin.im/tag/Flutter
Flutter知乎:https://zhuanlan.zhihu.com/flutter
Flutter布道者:
闲鱼技术团队
Flutter开源示例:
1.github.com/2d-inc/Hist…
2.flutterawesome.com
3.github.com/Solido/awes…
Flutter优秀开源项目:
一、Github客户端App
二、阿里拍卖团队Flutter开发者帮助App
三、开源中国App
四、仿网易云音乐App
五、仿书旗小说App
六、仿好奇心日报App
七、仿单读App