写点什么

10 天用 Flutter 撸了个高仿携程 App(附小技巧积累总结),小红书安卓面试题目

用户头像
Android架构
关注
发布于: 1 小时前

Widget build(BuildContext context) {final Animation<double> animation = listenable; // listenable 继承 AnimatedWidget,其实就是控制器,会自动监听组件的变化 return Container(height: 90,width: 90,child: Stack(overflow: Overflow.visible,alignment: Alignment.center,children: <Widget>[...// 扩散的圆线,其实就是用一个圆实现的,设置圆为透明,设置 borderPositioned(left: -((_sizeTween.evaluate(animation) - 90) / 2), // 根据 _sizeTween 动态设置 left 偏移值 top: -((_sizeTween.evaluate(animation) - 90) / 2), // 根据 _sizeTween 动态设置 top 偏移值 child: Opacity(opacity: _opacityTween.evaluate(animation), // 根据 _opacityTween 动态设置透明值 child: Container(width: isStart ? _sizeTween.evaluate(animation) : 0, // 设置 宽 height: _sizeTween.evaluate(animation), // 设置 高 decoration: BoxDecoration(color: Colors.transparent,borderRadius: BorderRadius.circular(_sizeTween.evaluate(animation) / 2),border: Border.all(color: Color(0xa8000000),)),),),),],),);}}

banner 组件

效果如图:



banner使用的是 flutter 的?[flutter_swiper](


)?插件实现的,代码如下:


Swiper(itemCount: bannerList.length, // 滚动图片的数量 autoplay: true, // 自动播放 pagination: SwiperPagination( // 指示器 builder: SquareSwiperPagination(size: 6, // 指示器的大小 activeSize: 6, // 激活状态指示器的大小 color: Colors.white.withAlpha(80), // 颜色 activeColor: Colors.white, // 激活状态的颜色),alignment: Alignment.bottomRight, // 对齐方式 margin: EdgeInsets.fromLTRB(0, 0, 14, 28), // 边距),itemBuilder: (BuildContext context, int index) { // 构造器 return GestureDetector(onTap: () {CommonModel model = bannerList[index];Navigator.push(context,MaterialPageRoute(builder: (context) => WebView(url: model.url,),),);},child: Image.network(bannerList[index].icon,fit: BoxFit.fill,),);},),


具体使用方法,可以去 flutter 的官方插件库?[pub.dev](


)?查看:[点击 flutter_swiper 查看](


)。


Tips:?需要注意的是,我稍改造了一下指示器的样式,flutter_swiper?只提供了 3 种指示器样式,如下:


  • dots = const DotSwiperPaginationBuilder(),圆形

  • fraction = const FractionPaginationBuilder(),百分数类型的,如:1/6,表示 6 页的第一页

  • rect = const RectSwiperPaginationBuilder(),矩形


并没有上图的激活状态的长椭圆形,其实就是按葫芦画瓢,自己实现一个长椭圆类型,如知详情,可[点击查看长椭圆形指示器源码](


)

浮动的 icon 导航

icon 导航效果如图:



icon 导航浮动在 banner 之上,其实用的是 flutter 的 Stack 组件,Stack 组件能让其子组件堆叠显示,它通常和 Positioned 组件配合使用,布局结构代码如下:


ListView(children: <Widget>[Container(child: Stack(children: <Widget>[Container( ... ), //这里放的是 banner 的代码 Positioned( ... ), //这个就是 icon 导航,通过 Positioned 固定显示位置],),),Container( ... ), // 这里放的网格导航及其他],),

渐变不规则带有背景图的网格导航

网格导航效果如图:



如图,网格导航分为三行四栏,而第一行分为三栏,每一行的第一栏宽度大于其余三栏,其余三栏均等,每一行都有渐变色,而且第一、二栏都有背景图;flutter 里 Column 组件能让子组件竖轴排列, Row 组件能让子组件横轴排列,布局代码如下:


Column( // 最外面放在 Column 组件 children: <Widget>[Container( // 第一行包裹 Container 设置其渐变色 height: 72,decoration: BoxDecoration(gradient: LinearGradient(colors: [ //设置渐变色 Color(0xfffa5956),Color(0xffef9c76).withAlpha(45)]),),child: Row( ... ), // 第一行),Padding(padding: EdgeInsets.only(top: 1), // 设置行直接的间隔),Container(height: 72,decoration: BoxDecoration(gradient: LinearGradient(colors: [ //设置渐变色 Color(0xff4b8fed),Color(0xff53bced),]),),c


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


hild: Row( ... ), // 第二行),Padding(padding: EdgeInsets.only(top: 1), // 设置行直接的间隔),Container(height: 72,decoration: BoxDecoration(gradient: LinearGradient(colors: [ //设置渐变色 Color(0xff34c2aa),Color(0xff6cd557),]),),child: Row( ... ), // 第三行),],),


其实,具体实现的细节还是很多的,比如:


  • 怎么设置第一栏宽度偏大,其他均等;

  • 第一行最后一栏宽度是其他的 2 倍;

  • 第一、二栏的别截图及浮动的红色气泡 tip 等;


在这里就不细讲,否则篇幅太长,如想了解详情?[点击查看源码](


)


其次,再来看看目的地页面功能及所用知识点,重点看下以下功能实现:


  • 左右布局 tabBarListView

  • 目的地搜索页面

左右布局 tabBarListView

具体效果如图:点击左边标签可以切换页面,左右滑动也可切换页面,点击展开显示更多等



其实官方已经提供了?tabBar?和?TabBarView?组件可以实现上下布局的效果*(旅拍页面就是用这个实现的)*,但是它无法实现左右布局,而且不太灵活,所以,我使用的是?[vertical_tabs](


)插件, 代码如下:


VerticalTabView(tabsWidth: 88,tabsElevation: 0,indicatorWidth: 0,selectedTabBackgroundColor: Colors.white,backgroundColor: Colors.white,tabTextStyle: TextStyle(height: 60,color: Color(0xff333333),),tabs: tabs,contents: tabPages,),),


Tips:这里需要注意的是:展开显示更多 span 标签组件的实现,因为,这个组件在很多的其他组件里用到而且要根据接口数据动态渲染,且组件自身存在状态的变化,这种情况下,最好是把他单独封装成一个组件(widget),否则,很难控制自身状态的变化,出现点击没有效果,或点击影响其他组件。

目的地搜索页面

效果如图:点击搜索结果,如:点击‘一日游‘,会搜索到‘一日游‘的相关数据



目的地搜索页面,大多都是和布局和对接接口的代码,在这里就不再赘述。


然后就是旅拍页面功能及所用知识点,重点看下以下功能实现:


  • 左右布局 tabBarListView

  • 瀑布流卡片

  • 旅拍搜索页

左右布局 tabBarListView

效果如图:可左右滑动切换页面,上拉加载更多,下拉刷新等



这个是 flutter 提供的组件,tabBar 和 TabBarView,代码如下:


Container(color: Colors.white,padding: EdgeInsets.only(left: 2),child: TabBar(controller: _controller,isScrollable: true,labelColor: Colors.black,labelPadding: EdgeInsets.fromLTRB(8, 6, 8, 0),indicatorColor: Color(0xff2FCFBB),indicatorPadding: EdgeInsets.all(6),indicatorSize: TabBarIndicatorSize.label,indicatorWeight: 2.2,labelStyle: TextStyle(fontSize: 18),unselectedLabelStyle: TextStyle(fontSize: 15),tabs: tabs.map<Tab>((Groups tab) {return Tab(text: tab.name,);}).toList(),),),Flexible(child: Container(padding: EdgeInsets.fromLTRB(6, 3, 6, 0),child: TabBarView(controller: _controller,children: tabs.map((Groups tab) {return TravelTabPage(travelUrl: travelParamsModel?.url,params: travelParamsModel?.params,groupChannelCode: tab?.code,);}).toList()),)),

瀑布流卡片

瀑布流卡片?用的是?[flutter_staggered_grid_view](


)?插件,代码如下:


StaggeredGridView.countBuilder(controller: _scrollController,crossAxisCount: 4,itemCount: travelItems?.length ?? 0,itemBuilder: (BuildContext context, int index) => _TravelItem(index: index,item: travelItems[index],),staggeredTileBuilder: (int index) => new StaggeredTile.fit(2),mainAxisSpacing: 2.0,crossAxisSpacing: 2.0,),

旅拍搜索页

效果如图:首先显示热门旅拍标签,点击可搜索相关内容,输入关键字可搜索相关旅拍信息,地点、景点、用户等


小技巧积累总结

以下都是我在项目里使用的知识点,在这里记录分享出来,希望能帮到大家。

PhysicalModel

PhysicalModel 可以裁剪带背景图的容器,如,你在一个 Container 里放了一张图片,想设置图片圆角,设置 Container 的 decoration 的 borderRadius 是无效的,这时候就要用到 PhysicalModel,代码如下:


PhysicalModel(borderRadius: BorderRadius.circular(6), // 设置圆角 clipBehavior: Clip.antiAlias, // 裁剪行为 color: Colors.transparent, // 颜色 elevation: 5, // 设置阴影 child: Container(child: Image.network(picUrl,fit: BoxFit.cover,),),),

LinearGradient

给容器添加渐变色,在网格导航、appBar 等地方都使用到,代码如下:


Container(height: 72,decoration: BoxDecoration(gradient: LinearGradient(colors: [Color(0xff4b8fed),Color(0xff53bced),]),),child: ...),

Color(int.parse('0xff' + gridNavItem.startColor))

颜色值转换成颜色,如果,没有变量的话,也可直接这样用 Color(0xff53bced),


  • ox:flutter 要求,可固定不变

  • ff:代表透明贴,不知道如何设置的话,可以用取色器,或者 withOpacity(opacity) 、 withAlpha(a)

  • 53bced: 常规的 6 位 RGB 值

Expanded、FractionallySizedBox

Expanded 可以让子组件撑满父容器,通常和 Row 及 Column 组件搭配使用;


FractionallySizedBox 可以让子组件撑满或超出父容器,可以单独使用,大小受 widthFactor 和 heightFactor 宽高因子的影响

MediaQuery.removePadding

MediaQuery.removePadding 可以移除组件的边距,有些组件自带有边距,有时候布局的时候,不需要边距,这时候就可以用 MediaQuery.removePadding,代码如下:


MediaQuery.removePadding(removeTop: true,context: context,child: ...)

MediaQuery.of(context).size.width

MediaQuery.of(context).size.width 获取屏幕的宽度,同理,MediaQuery.of(context).size.height 获取屏幕的高度;如,想一行平均 3 等分: 0.3 * MediaQuery.of(context).size.width,在目的地页面的标签组件就使用到它,代码如下:


Container(alignment: Alignment.center,...width: 0.3*MediaQuery.of(context).size.width - 12, // 屏幕平分三等分, - 12 是给每份中间留出空间 height: 40,...child: ...),

Theme.of(context).platform == TargetPlatform.iOS

判断操作系统类型,有时候可能有给 Andorid 和 iOS 做出不同的布局,就需要用到它。

with AutomaticKeepAliveClientMixin

flutter 在切换页面时候每次都会重新加载数据,如果想让页面保留状态,不重新加载,就需要使用 **AutomaticKeepAliveClientMixin,**代码如下:(在旅拍页面就有使用到它,为了让 tabBar 和 tabBarView 在切换时不重新加载)


class TravelTabPage extends StatefulWidget {...

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
10天用Flutter撸了个高仿携程App(附小技巧积累总结),小红书安卓面试题目