之前,也写过几篇关于 Flutter
的博文,最近,又花了一些时间学习研究 Flutter
,完结了高仿大厂 App 项目 (项目运用的接口都是来自线上实在App抓包而来,能够做到和线上项目相同的作用),也总结堆集了一些小技巧和常识点,所以,在这儿记载共享出来,也希望 Flutter
生态越来越好 (flutter开发App功率真的很高,Y K j d V R ! &开发体会也是很好的 )。
以下博文会分为4个部分概述:
- 项目g . j完结的功用预览
- 项目结构剖析
- 项目功用详细概述(所用常识点)
- 小技巧堆集总结
项目完结的功用预览
首要,咱们来经过一个视频来快速预览` N J , P下项目完结的功用和运转作用,如下
咱们看完视频,大概了解到,完结度基本能够和线上的App相差无异了,咱们如果对项目感兴趣,想了解详细怎样完结的,能够去我的 GitHub clone 源码检查。
本视频是用真机录屏的,由于,语音查找功用需z ! ~ 6 V O Q | R求录音,模拟器无法录音,当然, iOS
和 Andorid
都能够运转,作用是一样的,如图:
项目结构剖~ s 9 )析
其次,整理下项目的目录结构,了解每个文件都是干什么的,咱们先来看看一u U C h # $级目录,如下:
├── README.md # 描绘文件
├── andr0 9 U KoiY G I ? ; n ]d # android 宿主环境F a S X
├── build # 项目构建目录,由flutter主动完结
├── flutter_ctrip.iml
├── fonts # 自己创建的目录,用于寄存字体
├── images # 自己创建的目录,用于寄} + f E g e v G J存图片
├── ios # iOS 宿主环境
├── lib # flutter 执行文件,自己写的代码都在这
├── pubspec.lock # 用来记载锁定插件版本
├── pubspec.yaml # 插件及资源配置文件
└── test # 测验目录
这个就不; # # d e K 1 h r用多解说,大多是/ ! l z 9 0 flutter 生成及管理的,咱们需求重视的是 lib 目录。
咱们再来看看二级目录,如下 (要点重视下lib目录)
├── README.md
├── android
│ ├── android? c - R.iml
...
│ └── settings.gradle
├── build
│ ├── app
...
│ └── snapshot_blob.bin( H s S N ^ z @ ..d.fingerprint
├── flutter_ctrip.i, b m ( - 7 Lml
├── fV _ , _ U S S Ionts
│ ├── PingFang-ItalicI 9 Q g ` I.ttf
│ ├── PingFang-Regular.ttf
│ └── PingFang_Bold.ttf
├── images
│ ├── grid-nav-items-dingzhi.png
...
│ └── yuyin.png
├── ios
│6 i h ├── Flutter
...
│ └── ServiceDefinitions.json
├── lib
│ ├── dar % ? E D To # 恳求接口的类
│ ├── main.dart # flutter 进口文件
│ ├── model # 实体类,把服务器回来的 json 数据,转换成 dart 类
│ ├── navigatod R C | P v T r .r # boP W 6 ttom bar 主页底部导航路由
│ ├── pages # 所以的页面
│ ├── plugin # 封装的插件
│ ├── util # 东西类,避免重复代码,封装成东西类以便各个 page) / [ 调用
│G O c 6 └── widget # 封装的组件
├── pubspec.lock
├── ps r Q ] [ubspM o : k K Yec.yaml
└── test
└── widget_test.dart
再来看看,lib 目录下二级目录,看看整个项目创建了多少个文件,写了多少代码,如下 (其实,并不) ( 8 8 f c是许多)
├── daD k { N G S w O :o/
│ ├── destinatio= . +n_dao.dart*
│ ├── destination_search_dao.dart*
│ ├── home_dao.dart
│ ├── search_dao.dart*
│ ├── trave_hot_keyword_dao.dara , 7 / ] c bt*
│ ├── trave_search_dao.dart*
│ ├── trave_search_hot_dao.dart*
│ ├── travel_dao.dart*
│ ├── travel_params_dao.dart*
│ └── travel_tab_dao.dart*
├── main.u n 2 C xdart
├── modelW . 0 t/
│ ├── common_model.dart
│ ├── config_model.dart
│ ├── destination_mU / sodel.dart
│ ├── destination_search_model.da~ o f ; m f D Lrt
│ ├── grid_nL D f * - 4 s W lav_model.dart
│ ├── home_model.dart
│ ├── sales_box_model.dart
│ ├── seach_model.dart*
│ ├── travel_hot_ker Q g V K kyword_model.dart
│ ├── travel_model.dart*
│ ├── travel_parae w y W `ms_model.dart*
│ ├── travel_search_hot_models Y H 9.dart
│ ├── travel_search_model.dart
│ └── travel_tab_model.dart
├── navigat} ^ ` $ Lom 8 } ] # c 9r/
│ └── tab_navigater.dart
├── pages/
│ ├── destinatb - u q 1 | / # 3ion_page.dart
│ ├── destination_search_page.dart
│ ├── home_page.dart
│ ├── my_page.dart
│ ├── search_page.dart
│ ├── speak_page.dart*
│ ├── test_page.dart
│ ├── travel_page.dart
│ ├── tM g C ( Y xravel_search_page.da| G V [rt
│ └── travel_J t Z 2 y 5 s ;tab_page.dart*
├── plugin/
│ ├── asr_manager.dart*
│ ├── side_page_view.dart
│ ├── square_swiper_pagination.dart
│ └── vertical_tab_w 6 w 1 I # p 5 uview.dart
├── util/
│ └── navigator_util.dart*
└── widget/
├── grid_nav.dart
├── grid_nav_new.dart
├── loading_container.dart
├── local_nav.dart
├── salL _ f 1 ) r u ]es_box.dart
├── scalable_box.dart
├── search_bar.dart*
├── sub_nj g H 8 ] 6 z Hav.dart
└── webview.dart
整个项目便是w * m 0以上这些文件了 (详细的就不一个一个剖析了,如,感兴趣,咱们能够w h f ( Y m 2 ^ clone3 R 8 源码运转起来,自然就清除了)。
项目功用详细概述; F |(所用常识点)
首要,来看看主页. L 6功用及所用常识点,主页要点看下以下功用完结:
- 渐隐渐现的 appBq z v # !bar
- 查找组件的封装
- 语音 W u n Y : . D查找页面
- banner组件
- 起浮的 icon 导航
- 突变= t w G不规则带有背景图的网格导航
渐隐渐现的 appBbar
先来看看详细作用,一睹芳容,D ! F 8 . m r +如图:
翻滚的时分 appBar1 F 5 j W H ` Z Z 背景色从通明变成白色或白色变成通明,这儿首要用了 flutter 的 NotificationListener
组件,它会去监听组件树冒泡事情,当被它包裹的的组件 (子组件! E Q r d I 2 Y V) 发作改变时,Notification
回调函数会被触发,所以,经过它能够去监听页面的翻滚,来动态改动 appBar 的通明度 (alpha),代码如下:
NotificationListener(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollUpd9 E uateNotification &( * ^ n 3 K } E&
scrollNotification.depth == 0) {
_onScroll(scrr @ } J =ollNotificav / g o . qtion.metrics.pixels= , 9 y b C ^);
}
return true;
},
child: ...
Tips:
scrollNotification.depth
的值 0 表明其w + ; x { d r .子组件 (只监听子组件,不监听孙组件);
scrollNotification is ScrollU! 1 J 4 X y w ( xpdateNotification
来判别y + = L o / E U组件是否已更新,ScrollUp4 & ; Q | P j e KdateNotificad 1 a u n g & .tion 是 notifications 的生命周S W 4 q 7期一种状况,别离有一下几种:
- Sc, p k n N K 8 1rollStartNotification 组件开始翻滚
- ScrollUpdateNotification 组件方位现已发作改动
- ScrollEndNotification 组件中止翻i y # 9 , E k = e滚
- UserScrollNotification 不清楚
这儿,咱们不探求太深入,如想了解可多检查源码。
_onScroll 办法代码X w i ] w f 7如下:
void _onScq s # ` Kroll(offu L ` ` $ L 1 Y ?set) {
double alpha =K ; N L | offset / APPBAR_S& Z ,CROLL_OFFSET; // APPBAR_SCROLL_OFFSET 常量,值:100;offset 翻滚的间隔
//把 alpha 值操控值 0-1 之间
if (alpha < 0)h 0 x # ] s P {
alpha = 0;
} else if (alpha > 1) {
alpha = 1;
}
setState(() {
appBX f T Y S : z v 3arAlpha = alpha;
});
print(alpha);
}
查找组件的封装
查找组件作用如图:
以下是主x M + } d U 1 D页调用 searchBar
的代码:
SearchBar(
searchBarType: appBarAlpha > 0.2 //searchBar 的类:暗色、亮色
? SearchBarType.k } J & T KhomeLight
: SearchBarType.home,
inpul q stBoxClick: _jumpToSearchO , c ) 7 f p { 6, //点击回调函数
defg z x ]aultText: SEARCH_BC : Y JAR_DEFAULT_T_ j Q r } DEXT, // 提示文字
leftButtonClick: () {}, //左边边按钮点击回调函数
speakClic# e A fk: _jumpToSpeak, //点击话筒回调函数
rightButtonClick: _jumpToUser, //右边边按钮点击# D m回调函数
),
其实便是用 TextField
组件,再加一些样式,需求留意点是:onChanged,他是 TextField 用来监听文本框是否改变,经过它咱们来监听用户输入,来恳求接口数据;
详细的完结细节,请查阅源码: 点击检查searchBar源码
语音查找页面
语音查找n { } Z页面作用如图:由于模拟器无法录音,所以无法, _ # 3展现正常流程,如果录音识别成功后会回来查找页面,在项目预览视频中能够看到正常流程。
语音c e 0 d查找功用运用的是百度的言语识别SDK,原生接入之后,经过 MethodChannel 和原Y N Z k ; | `生Native端通信,这儿不做要点叙述(这儿会涉及原生Native的常识)。
要点看看点击录音按钮时的动画完结,这个动画用了 AnimatedWidget 完结k J G [ : _的,代码如E X P ~ C下:
class AnimaI / 8 G q N qtedWe5 t $ ! % x Sar extends AnimatedWidget {
final bool isStart;
static final _opacityTween = Tween<d9 f 6 , q ; $ *ouble>(begin: 0.5, end: 0); // 设置4 * y 2 Y $ F )通明Z 8 ! D度改变值
static final _sizeTween = Tween<double>(begin: 90, end: 260); // 设置圆形线的分散值
AnimatedWear({Key key, this.isStart, Animation! 3 # j v G A<double> animation})
: super(key: key, listE v # r C Q _enable: animation);
@override
WK n ( 5 * ^idget build(BuildContext cO O montext) {
final AnimationY N n r Q B f z m<double> animation = listenable; // listenable 继承 AnimatedWidget,其实便是操控器,会主动监D q n ; Y )听组件的改变
retu= % @ A 9 4rn Container(
height: 90,
width:7 L L Y 90,
child: Stack(
overflg 5 V | k R v }ow: Overflow.visible,
alignment: AlignmenQ ; | & O H J dt.center,
children: <Widget[ L $ 7>[
...
// 分散的圆线,其实便是用一个圆完结的,设置圆为通明,设置border
Positioned(
left: -((_sizeTween.ev[ ( ] d a 7 galuate(animation) - 90) / 2h l s ( ^ m ,), // 根据 _sizeTween 动态设置left偏移值
top: -((_sizeTween.& * Y D Oevaluate(animation) - 90) / 2), // 根据 _sizeTween 动态设置top偏移值
child: Opacity(
opacity: _opacityTween.evaluate(anO t w k c u oimation), // 根据 _opacityTween 动态设置通明值
child:9 ! _ J K , ` Container(
width: isStart ? _sizeTween.evaluate(animation% q i $) : 0, // 设置 宽
height: _sizeTween.evaluat$ ` 6 }e(animation), // 设( @ { a 7 n置 高a e G * = 5 D
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(
_sizeTween.evaluate(animation) / 2),
border: Border.all(
color: Color(0xa8000000),
)),
),
),
),
],
),
);
}
}
其他细节,如:点击时提示录音,录音失败提示,点击录音按钮出现半通明[ U f Y黑色圆边框,中止后消失等,请检查源; d O A 7 [ [ r *码。
banner组件
作用如图:
banner
运用的是flutter的 flutter_sw9 u riper 插件完结的,代码如下:X R r v O
Swiper(
itemCount: bannerList.lengtw n w = p A sh, // 翻滚图片的数量
autoplay: true, // 主动播放
pagination: SwipC e 1 * erPagination( // 指示器
builder: SquareSwiperPagination(
size: 6, // 指示器的大小
activeSize: 6, // 激活状况指示器的大小
color: Colors.white.withAlphaS S * J H S(80), // 色彩
activeColor: Colors.white, // 激活状况的色彩
),
alignment: Alignment.bottomRight, // 对齐方式
margin: EdgeInsets.fro; ~ ~ y Q k x ]mLTRB(0, 0, 14, 28), // 边距
),
itemBS U z B + 9uilder: (BuildContext context, int index) { // 构造器
return GestureDetector(
onTap: () {
CommonModel mode% 1 J Sl = bannerList[index];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WebView(
url: model.url,
),
),
)h k o;
},
child: Image.netr j p C b t 1 2work(
bannerList[index].icon,
fit: BoxFie x B & m t 3 it.fill,
),
);
},
),
详细运用办法,能够去 flutter的官方插件库 pub.dev 检查:点击flutter_swiper检查。
Tips:
需求留意的是,我稍改造了一下指示器的样式,K b V Y l V H [ Hflutter_swiper
只供给了 3 种指示器样式,如下:
- dots = const DotSwiperPaginationBuilder(),圆形
- fraction = const FractionPaginationBuilder(),百分数类型的,如:1/6,表明6页的榜首页
- rect = const RectSK { F VwiperPaginationBuilder(),矩形
并没有m ; ] h a F上图的激活状况的长椭圆形l g [ 2 l } O,其实便是按葫芦画瓢,自己完结一个长椭圆类型,如知概况,可点击检查长椭圆形指示器源码
起浮的 icon 导航
icon导航作用如图:
ic[ 0 ` Ron导航起浮在banner之上,其有用的是 flutter
的 Stack 组件,Stack 组件能让其子组件堆 x P P Q U , b F叠显现,它通常和 Positioned 组件k f D P g B i合作运用,布局结构代码如下:
ListView(
children:= u A C s X <Widget>l Y U x v * R I[
Container(
child: SN T $ | J ] n 5 Etack(
chl ] ~ a P j S Fildren: <W c J w X n o VWidget>[
Container( ... ), //这儿放的是bannZ S Z Ser的代码
Positioned( ... ), //这个便是icon导航,经过 PositioneE u A Y v md 固定显现方位
],
)A w a / 5 q . L,
),
Container( ... ), // 这儿放的网格导航及其他
],
),
突变不规则带有背t Z d V 8 x景图的网格导航
网格导航作用如图:
如图,网格导航分为三行四栏/ 9 %,而榜首行分为三栏,每一行的榜首栏宽度大于其他三栏,其他三栏平等,每一行都有突变色,并且榜首、二栏都有背景图;
flutter
里 Column 组件能让子组件竖轴排列, Row 组件能让子组件横轴排列,布@ r –局代码如下:
Column( /& C * i j H )/ 最外面放在 Col~ 6 tumn 组件
child6 f % ~ren: <Widget>[
Container( // 榜首行包裹 Container 设置其突变色
he] g a % b .ight: 72,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [ /b & R/设置突变色
Color(0xfffa5956),
Color(0xffef9c76).withAlp] U Sha(45)
]),
),
child: Row(% 7 M t ~ ... ), // 榜首行
),
Padding(
padding: EdgeInsets.only(top: 1), // 设置行直接的间隔
),
Container(
height: 72,
decoration:+ r V b BoxDecoration(
gradient: LinearGradient(colors: [ //设 Q ]置突变色
Color(0xff4b8fed5 3 p } -),
ColoO C N ) q 6 yr(0xff53bced),
]),
),
child: Row( ... ), // 第二行
),
Padding(
padding: EdgeInsets.only(top: 1), // 设置行直接的间隔
),
Container+ E ? # d v(y # k # 4 Q :
h. _ J + n ;eight: 72,
decoration: BoxDU - e @ecoration(q ( N - ;
gradient: LinearGradient(b = s ) 0 P ccolors: [ //O b =设置突变色
Color(0xff34c2aa),
Color(0xff6cdu z P R G ` J A557),
]),
),
child: Row( ... ), // 第三行
),
],
),
其实,详细完结的细节还是许多的B k p : c,比方:
- 怎样设置榜首栏宽度偏大,其他平等;
- 榜首行最后一栏宽度是其他的2倍;
- 榜首、二栏的背景图及起浮的红色– R u q气泡tip等;
在这儿就不细讲,不然篇幅太长,如想了解概况 点` : }击e r w ) * B R检查源码
其次,再来看看目的地页面功9 y % R ; m用及Q V D c I k所用常识点,要点看下以下# E w # G功用完结:
- 左右布局tabBarListView
- 目的地查找页面
左右布局tabBarListView
详细作用如图& } a w:点击左边标签能够切换页面,左右滑动也可切换页面,X & B { * w v点击打开显现更多等
其实官方现已供给了 tabBar 和 TabBarView 组件能够完结上下布局的作用 (旅拍页# } 0 M M 3 2 k (面便是用这个完结的),但是它无法完结左右布局,并且不太灵敏,所以,我运用的是 verb O 5 o : 8 r –tical_tabs插件, 代Y 2 h 6 i l + 8码如下:
VerticalTabView(
tabsWidth: 88,
tabsElevation: 0,
indicatorWid3 P T A N X zth: 0,
selectedTabBackgroundColor: Colors.white,
backgroundColor: Colors.white,g A ~
tabTeU H o a h B GxtStyle: TextStyle(
height: 60,
color: Color(0xff333333),
),
tabs: tabs,
contJ T H e $ ~ Kents: tabPages,
),
),
详C + n – B ; v S e细运用办法,在这儿就不赘述了,点击vertical_tabs检查
这儿需求留意的是:打开显现更多span标签组件的完结,由于,这个组件在许/ g b a R多的其他组件里用到并且要根据接口数据动态烘托,且组件自身存在状况的改变,这种状况下,最好是把他单独封装成一个组件(widge1 J s | D A =t)G a s k A / M A,不然,很难操控自身状况的改变,出现点击没有作用,或点击影响其他组件。
目的地查找页面
作用如图:点击查找成w V b 7 M : – (果,如:& o t 4 * = 9 `点击‘一日游‘,会查找到‘一日游‘的相关数据
目的地查找页面,大多都是和布局和对接接口的代码,在这儿就不再h ( M G 4 o P t a赘述。
然后便是旅拍页面功用及所用常识点,要l z ( Y 3 #点看下以下功用完结:
- 左右布局tabBarListView
- 瀑布流卡片
- 旅拍查找P F m E M t 5 J {页
左右布局tabBarListView
作用如图:可左右滑动切换页面,上拉加载更多,下拉改写等
这个是flutter
供给的组件,tabBar 和 TabBarView,代码如下:
Container(
color: ColoT 7 W N % 9 Zrs.white,
padding: EdgeInsets.only(left: 2),
child: TabBar(
controller: _controller,
isScrollable: true,
labelColor: Colors.black,
labelPaddin% | ` F 4 h 0 qg: EdgeInsetsI s { V #.fromLTRB(8, 6, 8, 0),
indicatorColor: Colorb ; E l / k z C :(0xff2FCFh ` c %BB),
indicatorPadding: EdgeInsete b u _ P Vs.all(6),
indicatorSize: TabBarIndicatorSiz8 L Se.label,
indicatorWeightu 0 j: 2.2,
labelStyle: TextStyle(foG n Y IntSize: 18),
unselectedLabelStyle: TextStyle(fontSize: 15),
tabs: tabs.map<Tab>((Groups tab) {
return Tab(
tex7 # Yt: tab.name,
);
}. b B ~ l).toList(),
),
),
Flexibl1 A t Ge(
child: Cont3 H - I [ainer(
padding: EdgeInsets.fromLTRB(6, 3, 6, 0),
child: TabBarVie- ` u ? ? Q _w(
controller: _controller,
children: tabs.map((Groups tab) {
return TravelTabPage(
travelUrl: travelParamsMode X T G / k Q )l?.url,
params: travelParamsModel?.params,
groV } c D r ( ) pupChannelCode: tab?.code,
);
}).toList()),
)),
瀑布流卡片
瀑布流卡片 用的是 flute Z k v 2 ( ? 5 Dter_staggered| J C_grid_view 插件,代码如下:
StaggeredGridView.countBuilder(
controller: _scrollController,
crossAxisCounH j M K 4 l $ st0 u 3 k: 4,
itemCount: travelItemF b $s?.lengtn } C Nh ?? 0,
itemBuilder: (BuildContext context, int index) => _TravelItem(
index: index,
item: travelItems[index],
)2 ( [,
staggeredTileBuilder: (9 Q uint index) => new StaggeredTile.fit(2),
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0,
),
如下了解更多相关信息,点击flutter_staggered_grid_view检查。
旅拍查找页
作用如图:首要= T 7 u f B f 8 Q显现热门旅拍标签,V E h ^ # ^ Y W E点击可查找相关内容,输入关键字可查M | x 4 4 , [ @找相关旅拍信息,地点、景点、b S G g (用户等
旅拍查找页,大多也是和布局和对接接口的代码,在这儿就不再赘述。
小技巧堆集总结
以下都是我在项目里运用的常识点,在这儿记载O U . @ 9 A ^ =共享出来,希望能帮到咱们。
PhysK 5 [ k ] C V AicalModel
PhysicalModel 能够裁剪带背景图的容; } k 4 0 d ? W器,如,你在一个 Container 里放了一张图片,想设置图片圆角,设置V U M ) X y j F | Container 的 decoration 的 bor$ k J TderRadius 是无s f G 4效的,这时分就要用到 PhysicalModel,代码如下:
PhysicalModel(
borderRadius: BorderRadius.circular(6), // 设置圆角
clipBehavior: Clip.antiAlias, // 裁剪行为
cH ( | P zolor: Colors.tran3 } Psparent, // 色彩
elevation: 5, // 设置阴影
child: Container(
child: Image.network(
picUrl,
fit: BoxFit.cover,
),
),
),
LinearGradient
给容器增加突变色,在网格导航、appBar等地方都运用到,代码如下:
Container(
height: 72,
decorati] b ^ ! A Son7 3 e: BoxDecoration(
gradient: LinearGradient(colors: [
Color(0xff4b8fed),
Color(0xff53bced),
]),
),
child: ...
),
Color(int.parse(‘0xff’ + gridNavItem.startColor))
色彩值转换成色彩,如果,没有变量的话,也可直接这样用 Color(0xff53bced)
,
- ox:flutter要t p k求,可固定不变
- ff:代表通明度,不知道怎么设置的话,能够用取色器,或者 withOpacity} C – & 8(opacity) 、 withAlpha(a)
- 53bced: 惯例的6位RGB值
Expanded、FracM m }tion* . C fallySizl I 8 pedBox
Expanded 能够让子组件v j 8撑满父容器,通常和 Ron E ? zw 及 Column 组件调配A } E运用;
FractionallySizedBox 能够让e ; x子组件撑满或超出父容器,能够单独运用,大小受 widthFactor 和 heightFactor 宽高因子e T C 8 G @ l的影响
MediaQuery.remo! c d $ W bvePadding
MediaQue, . } * F 1 U ,ry.removePadding 能够移除组件的边距,有些组件自带有边距,有时分布局的时分,不需求边距,这时分就能够用 MediaQuery.removePadding,代码如下:
MediaQuery.removePadding(
removM , }eTop: true,
context: context,
chk z , F yild: ...
)
MediaQuery.ofc ( Z(context).size.width
MediaQuery.of(context).size.width 获取屏幕的宽度,同理,MediaQue} c 6 r 8ry.of(context).sizC i 9 o 1 8 Be.height 获取屏幕的高度;
如,想一行均匀3等分: 0.3 * MediaQuery.of(context).size.widtho = # Y v .,在目的地页面的标签组件就运用到它,代码如下:
Container(
alignment: Alignment.center,
...
width:$ 4 @ A Z r H { 0.3*MediaQuery.of(context).size.width -4 6 T ^ m Z 2 9 12, /[ 5 c _/ 屏幕平分三等分,z Z i h H - 12 是给每份中心留出空间
height: 40,
...
child: ...
),
Theme.of(context).platform == TargetPlatform.iOS
判别操作系统类型,有时分可能有给 Andorid 和 iOS 做出不同的布局,就需求用到它。
with AutomaticKeepAliveCl0 1 rin W W g ~ CentMixin
flutter
在切换页面时分每次都会从头加载数据,如果想让页面保留状况,不从头加载,就需求运用 AutomaticKeepAliveClientMixin,代码如下: g X c Q B(在旅拍页面就有运用到它,为了让tabBar 和 tabBarView在. A F r + S m . i切换时不从h x 6 头加载)
class TravelTabPage extends StatefulWidget {
...
//需求重写 wantKeepAE . , T ) f / Flive 且 设置成 true
@override
bool get wantKeepAlive => true;
}
暂时只能想到这些常Y O j h m 用的常识点,今后如有新的会渐渐补充。
博客地址: lis 9 R y u n & Uhaoy.net
博客Notes地址: h.lishaoy.net
项目GitHub地址: github.com/persilee/flB ! S b 8 m…