目的地搜索页面

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

no-shadow

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

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

  • 左右布局tabBarListView

  • 瀑布流卡片

  • 旅拍搜索页

左右布局tabBarListView

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

no-shadow

这个是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,
),

如下了解更多相关信息,点击flutter_staggered_grid_view查看

旅拍搜索页

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

no-shadow

旅拍搜索页,大多也是和布局和对接接口的代码,在这里就不再赘述。

小技巧积累总结

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

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 {
  ...  //需要重写 wantKeepAlive 且 设置成 true
  @override
  bool get wantKeepAlive => true;
}

暂时只能想到这些常用的知识点,以后如有新的会慢慢补充。

博客地址: https://lishaoy.net
博客Notes地址: https://h.lishaoy.net
项目GitHub地址: https://github.com/persilee/flutter_ctrip