Flutter实战详解--高仿好奇心日报,阿里P7亲自讲解
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。还有高级架构技术进阶脑图、Android开发面试专题资料帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
首先在pubspec.yaml中导入
dependencies: json_annotation: ^2.0.0 dev_dependencies: build_runner: ^1.0.0 json_serializable: ^2.0.0
创建一个model.dart文件 引入文件
import ‘package:json_annotation/json_annotation.dart’; part ‘model.g.dart’;
其中这个model.g.dart等会儿会自动生成.这里需要掌握两个知识点
1.@JsonSerializable() 这是表示告诉编译器这个类是需要生成Model类的 2,@JsonKey 由于服务器返回的部分数据名称在Dart语言中是不被允许的,比如has_more,Dart中命名不能出现下划线,所以就需要用到@JsonKey来告诉编译器这个参数对于json中的哪个字段
@JsonSerializable()
class Feed {
String image;
int type;
@JsonKey(name: ‘index_type’)
int indexType;
Post post;
@JsonKey(name: ‘news_list’)
List newsList;
Feed(this.image,this.type,this.post,this.indexType,this.newsList);
factory Feed.fromJson(Map<String,dynamic> json) => _KaTeX parse error: Expected group after '_' at position 54: …c> toJson() => _̲FeedToJson(this);
}
好了,写完后会报错,因为FeedFromJson和FeedToJson没有找到,这个时候在控制到输入flutter packages pub run build_runner build指令后会自动生成一个moded.g.dart文件,于是在网络请求下来数据后就可以用Feed feed = Feed.fromJson(data)这个方法来将Json中数据转换保存在Feed这个实例中了.在model类中还有些复杂的Json嵌套,但是也都很简单,大家看一眼应该就会了,哈哈.JSON和序列化具体教程
5.轮播图
Flutter中的轮播图我用到了Flutter_Swiper这个组件,这里设置小圆点属性的时候稍微麻烦了点,网上好像也没有讲到,我这里讲一下. 首先要创建DotSwiperPaginationBuilder
DotSwiperPaginationBuilder builder = DotSwiperPaginationBuilder(
color: Colors.white,//未选中圆点颜色
activeColor: Colors.yellow,//选中圆点颜色
size:7,//未选中大小
activeSize: 7,//选中圆点大小
space: 5//圆点间距
);
然后在Swiper中的pagination属性中设置它
pagination: new SwiperPagination(
builder: builder,
),
- 网络请求 首先,展示页面要继承自
StatefulWidget,因为需要动态更新数据和列表. 网络请求插件我用的Dio,非常好用. 在initState方法中请求数据表示刚加载页面的时候进行网络请求,请求数据方法如下
void getData()async{
if (lastKey == ‘0’){
dataList = [];//下拉刷新的时候将DataList制空
}
Dio dio = new Dio();
Response response = await dio.get(“ u r l url urllastKey.json”);
Reslut reslut = Reslut.fromJson(response.data);
if(!reslut.response.hasMore){
return;//如果没有数据就不继续了
}
if(reslut.response.columns != null) {
columnList = reslut.response.columns;
}
lastKey = reslut.response.lastKey;//更新lastkey
setState(() {
if (reslut.response.banners != null){
banners = reslut.response.banners;//给轮播图赋值
}
dataList.addAll(reslut.response.feeds);//给数据源赋值
});
}
因为用到了setState()方法,所以在该方法中改变了的数据会对其相应的地方进行刷新,比如设置了ListView的itemCount个数为dataList.length,如果在SetState方法中dataList.length改变了,那么ListView的itemCount树也会自动改变并刷新ListView.
7. 上拉刷新与加载
Flutter中有RefreshIndicator用于下拉刷新,它有个onRefresh闭包方法,表示下拉的时候执行的方法,一般用于网络请求.onRefresh方法如下
Future handleRefresh() {
final Completer completer = Completer();
Timer(const Duration(seconds: 1), () {
completer.complete();
});
return completer.future.then(() {
lastKey = ‘0’;
getData();
});
}
下拉加载的话需要初始化一个ScrollController,将它设为ListView的controller,并对其进行监听,当滑动到最底部的时候进行网络请求.
@override
void initState() {
url = widget.url;
getData();
_scrollController.addListener(() {
///判断当前滑动位置是不是到达底部,触发加载更多回调
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
getData();
}
});
}
final ScrollController _scrollController = new ScrollController();
上拉加载loading框用到了flutter_spinkit插件,提供了大量的加载样式.

代码如下
///上拉加载更多
Widget _buildProgressIndicator() {
///是否需要显示上拉加载更多的loading
Widget bottomWidget = new Row(mainAxisAlignment: MainAxisAlignment.center, children: [
///loading框
new SpinKitThreeBounce(color: Color(0xFF24292E)),
new Container(
width: 5.0,
),
]);
return new Padding(
padding: const EdgeInsets.all(20.0),
child: new Center(
child: bottomWidget,
),
);
}
8. ListView赋值
由于最上面有一个轮播图,最下面有加载框,所以ListView的itemCount个数为dataList.length+2,又因为每个item之间都有一个浅灰色的风格线,所以需要用到ListView.separated,具体代码如下:
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh:(()=> _handleRefresh()),
color: Colors.yellow,//刷新控件的颜色
child: ListView.separated(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: _getListCount(),//item个数
controller: _scrollController,//用于监听是否滑到最底部
itemBuilder: (context,index){
if(index == 0){
return SwiperWidget(context, banners);//如果是第一个,则展示banner
}else if(index < dataList.length + 1){
return WidgetUtils.GetListWidget(context, dataList[index - 1]);//展示数据
}else {
return _buildProgressIndicator();//展示加载loading框
}
},
separatorBuilder: (context,idx){//分割线
return Container(
height: 5,
color: Color.fromARGB(50,183, 187, 197),
);
},
),
);
}
9. ListView嵌套横向滑动ListView
这种的话也稍微复杂一点,有两种样式.并且到滑到最右边的时候可以继续请求并加载数据.


首先来分析一下数据

这个colunmns就是横向滑动列表的重要数据.

里面的id是请求参数,show_type表示列表的样式,location表示插入的位置.而且通过抓取接口发现,当横向列表快要展示出来的时候,才会去请求横向列表的具体接口. 那么思路就很清晰了,在请求获得数据后遍历colunmns,根据每个colunmn的location插入一个Map,如下
data.insert(colunm.location, {‘id’:colunm.id,‘showType’:colunm.showType});
,再创建一个ColumnsListWidget类,继承自StatefulWidget,是一个新item,在滑动到该列表的位置的时候,会将该Map数据传给ColumnsListWidget,这个时候ColumnsListWidget就会加载数据并展示出来了,滑到最右边的时候加载和滑到最底部加载的方法一样,就不多说了.具体可以查看源码,关键代码如下:
static Widget GetListWidget(BuildContext context, dynamic data) {
Widget widget;
if(data.runtimeType == Feed) {
if (data.indexType != null) {
widget = NewsListWidget(context, data);
} else if (data.type == 2) {
widget = ListImageTop(context, data);
} else if (data.type == 0) {
widget = ActivityWidget(context, data);
} else if (data.type == 1) {
widget = ListImageRight(context, data);
}
}else{
widget = ColumnsListWidget(id: data[‘id’],showType: data[‘showType’],);
}
1.横向ListView外需要用
Flexible包裹,Flexible组件可以使Row、Column、Flex等子组件在主轴方向有填充可用空间的能力(例如,Row在水平方向,Column在垂直方向),但是它与Expanded组件不同,它不强制子组件填充可用空间。 2.ListView初始位置用到padding: new EdgeInsets.symmetric(horizontal: 12.0),用padding: EdgeInsets.only(left: 12)的话会让ListView和最左边一直有条线
10.webview加载复杂的Html字段

获取到网页详情的数据发现是Html字段,并且其中的css是url地址,试了很多Flutter加载Html的插件发现样式都不正确,最后决定使用原生和Flutter混编,这时候发现flutter_webview_plugin这个插件是使用原生网页的,不过它只支持加载url,于是就需要做一些修改.
- iOS 在
FlutterWebviewPlugin.m文件中的- (void)navigate:(FlutterMethodCall*)call方法中的最后一排,将[self.webview loadRequest:request]方法改为[self.webview loadHTMLString:url baseURL:nil] - Android 在
WebViewManager.java文件中webView.loadUrl(url)方法改为webView.loadData(url, "text/html", "UTF-8"),以及下面那排的void reloadUrl(String url) { webView.loadUrl(url); }改为void reloadUrl(String url) { webView.loadData(url, "text/html", "UTF-8"); }由于服务器端返回的Html中的css和js文件地址是/assets/app3开头的,所以需要替换成绝对路径,所以要用到这个方法htmlBody.replaceAll( '/assets/app3','http://app3.qdaily.com/assets/app3')好了,这下就可以呈现出漂亮的网页了.
11.ListView嵌套GridView
在点击横向滑动列表的总标题的时候,会进入到相关栏目的详情页,如图

这个ListView包含上下两部分.上面这部分为:

结构如下

下面就是一个GridView,不过有时候下面会是ListView,根据showType字段来判断,GridView的代码如下:
Widget ColumnsDetailTypeTwo(BuildContext context,List feesList){
return GridView.count(
physics: NeverScrollableScrollPhysics(),
crossAxisCount: 2,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 15.0,
childAspectRatio: 0.612,
padding: new EdgeInsets.symmetric(horizontal: 20.0),
children: feesList.map((Feed feed) {
return ColumnsTypeTwoTile(context, feed);
}).toList()
);
}
其中 childAspectRatio表示宽高比.
圆角头像需要用到
CircleAvatar(backgroundImage:NetworkImage(url),),这个控件
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。





既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。



网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
更多推荐


所有评论(0)