底部导航:
组件:BottomNavigationBar
底部需要多个:type::BottomNavigationBarType.fixed
改变点击时的颜色:fixedColor:Colors.red
适配器&轮播图
固定宽高闭:AspectRation
aspectRatio: 2 / 1,//宽高比
可以用来防止服务器返回图片大小不一致导致高度不一致
轮播图组件:Swiper
autoplay:false//自动播放
pagination:new SwiperPagination()//展示默认分页指示器
屏幕适配器:
1、dependencies:
flutter_screenutil: ^0.6.0
2、import 'package:flutter_screenutil/flutter_screenutil.dart';
3、封装成一个类
4、在各个组件使用需要先初始化: ScreenAdapt.init(context);
JSON数据的序列化与反序列化
序列化:从服务器得到的数据装换成Map
两种方法:
手动序列化
使用dart:convert中的json.decode
适合较小的项目,当在较大项目时容易出错,字母母拼写错误出现不存在字段就会造成崩溃
自动化序列:使用JSON to dart工具将字符串转换成模型类
var focus = FocusModel.fromJson(json.decode(str));
后面就可以直接使用
print(focus.sId);
print(focus.title);
注意有图片地址需要处理
pic.replaceAll('\\','/')
反序列化:把一个Map转换成字符串 encode
列表
组件:ListView
横向列表滑动:ScrollDirection:Axis.horizontal//改变主轴方向
页面布局:
组件:wrap
可以实现流式布局,从左到右,从上到下
spacing:主轴方法的间距
runpacing:row之间距离
alignment:主轴对齐方法
手势添加点击事件
组件:InkWell
onTap(){}单击需要触发功能
onDoubleTap:双击事件触发
onLongPress:长按触发事件
填充控件:
组件Pading
给子控件插入指定的填充
1.当child为空的时候,会产生一个宽为left+right,高为top+bottom的区域;
2.当child不为空的时候,Padding会将布局约束传递给child,根据设置的padding属性,缩小child的布局尺寸。然后Padding将自己调整到child设置了padding属性的尺寸,在child周围创建空白区域
定位
Stack+Positioned(设置子元素、定位)
Stack+Align(alignment: Alignment.centerLeft,)
Map().toList()//转换成list
width: double.infinity,//强制在宽度上撑满,不设置,则根据child和父节点两者一起布局
返回是不重新请求数据:
1.添加with AutomaticKeepAliveClientMixin
2.bool get wantKeepAlive=>true;(第一个组件)
3.bool get wantKeepAlive=>true(第二个组件)
从第一个页面到这里第二个页面再返回后第一个页面使用原来缓存数据不会再调用initState重新请求数据
下拉刷新,上拉加载更多
下拉刷新:
直接使用 RefreshIndicator 组件,
onRefres为重新获取数据的方法
onRefresh: _onRefresh,
// 下拉刷新
Future<void> _onRefresh() async {
await Future.delayed(Duration(milliseconds: 1000), () {
_getProductListData();
});}
上拉加载更多:
主要通过 ScrollController控制器
1. ScrollController _scrollController=ScrollController();
int _page=1;//定义页数
int _pageSize=8;//每页有多少条数据
List _productList=[];//数据
bool flag=true;//解决重复请求的问题
bool _hasMore=true;//是否有数据
2.监听滚动条滚动事件
_scrollController.addListener((){
// _scrollController.position.pixels //获取滚动条滚动的高度
// _scrollController.position.maxScrollExtent//获取页面高度
if(_scrollController.position.pixels>_scrollController.position.maxScrollExtent-20){
if(this.flag && this._hasMore){
_getProductListData();
}
}
});
3.获取数据
_getProductListData()async{
....
if(productList.result.length<this._pageSize){
this._productList=productList.result;//新的数据放到_productList,老的数据会丢弃了,不适合
this._productList.addAll(productList.result);//把每一页的数据拼接放到 _productList
}else{
....
this._page++;
....
}
}
4.
// 显示加载中的小圈圈
Widget _showMore(index){
if(this._hasMore){
return (index==this._productList.length-1)?LoadingWidget():Text("");
}else{
return (index==this._productList.length-1)?Text("--我是有底线的--"):Text("");
}
}
5.不要忘记在使用的地方监控 controller: _scrollController,
加载小圈圈
组件CircularProgressIndicator
属性:strokeWidth//圆圈线条宽度
侧边栏
左侧:Drawer组件
右侧:endDrawer
打开抽屉菜单:
1.在 ScaffoldState 中,通过 Scaffold.of(context) 可以获取父级最近的 Scaffold Widget 的 State 对象
2.Flutter 还有一种通用的获取StatefulWidget 对象 State 的方法:通过 GlobalKey 来获取! 步骤有两步:
1)给目标 StatefulWidget 添加 GlobalKey
//定义一个globalKey,由于GlobalKey要保持全局唯一性,我们使用静态变量存储
static GlobalKey<ScaffoldState> _globalKey= new GlobalKey();
...
Scaffold(
key: _globalKey , //设置key
...
)
2)通过GlobalKey来获取State对象
_globalKey.currentState.openDrawer()//默认打开左侧栏
滚动列表页面
PageView组件
int _currentIndex = 0;
void initState(){
...
//默认第一页
this._pageController=new PageController(initialPage: this._currentIndex);
}
PageView(
controller: this._pageController,//当前显示页面
children: this._PageList,//显示的列表
onPageChanged: (index){
setState(() {
this._currentIndex=index;
});
},
physics:NeverScrollableScrollPhysics(),//禁止PageView滑动
)
路由
Navigator.pushReplacementNamed(context, '/page1',)
指把当前页面在栈中的位置替换成跳转的页面(替换导航器的当前路由,通过推送路由[routeName]),当新的页面进入后,之前的页面将执行dispose方法。返回时直接返回到page1页面的上一个页面
弹出框
1、showDialog
barrierDismissible: false,//点击灰色背景的时候是否消失弹框
2.底部弹出框:showModalBottomSheet
默认点击消失,可以给子组件外面包一层GestureDetector并设置onTap返回false,拦截点击事件使点击底部面板区域,面板不消失。
底部面板的高度是有限制的,不能设置全屏高度
点击不消失:
return GestureDetector(
onTap: () => false,
);