Flutter一步步实现x程GridNav网格布局_hotel布局与完结

926 阅读4分钟

# 本文收获与价值

看完本系列文章后你将能够做出如下100%还原携程 V8.22.0 首页 GridNav 的界面:

# 准备工作

开始前请

  1. 按照Flutter一步步实现x程GridNav网格布局_准备工作中的步骤完成准备工作;

  2. 按照Flutter一步步实现x程GridNav网格布局_整体布局中添加相关代码;

注: 以下全部代码改变都在grid_widget.dart文件中机进行;

# 实现hotel行的布局

  1. // todo: add hotel row 替换为

    child: Row(
      children: <Widget>[
        // todo: add hotel row items
      ],
    ),
    
  2. Widget _travelRow(){... 函数下面添加如下代码实现

    // todo: add imageUrl, imgWidth,title. 
    Widget _firstBGimageStack() {
      return Expanded(
        child: FractionallySizedBox(
          widthFactor: 1,
          heightFactor: 1,
          child: Stack(
            alignment: Alignment.bottomRight,
            children: <Widget>[
              _bgImagePositioned(
                _hotelBGImageUrl,
                width: imgWidth,
              ),
              _firstTitlePositioned('酒店'),
            ],
          ),
        ),
        flex: 31,
      );
    }
    
    Widget _firstTitlePositioned(String title) {
      return Positioned(
        left: 15,
        top: 25,
        child: Text(
          title,
          style: _titleStyle,
        ),
      );
    }
    
    Widget _bgImagePositioned(String imageUrl, {double width = 73}) {
      return Positioned(
        child: Image.network(
          imageUrl,
          width: width,
          fit: BoxFit.fill,
        ),
      );
    }
    
    

    注意:

    • _firstBGimageStack 中的 flex: 31 是根据网页端的flex布局的比例来的,下文中 flex: 23flex 46 等均是如此;

    • FractionallySizedBox(widthFactor: 1,heightFactor: 1)是用来撑满父节点整个布局空间用的,widthFactor: 1 代表比例表示占满宽, heightFactor: 1表示占满高度;

  3. 将如下代码添加到 // todo: add hotel row items 的下方

    _firstBGimageStack(),
    

    保存更改cmd+s,界面热更新如下

  4. Widget _bgImagePositioned(){... 函数下方添加第二列带有背景图的 Stack 布局代码(包括添加左边框):

    // todo: add imageUrl, imgWidth,title. 
    Widget _secondBGImageStack() {
      return Expanded(
        child: FractionallySizedBox(
          widthFactor: 1,
          heightFactor: 1,
          child: Container(
            decoration: BoxDecoration(
              border: Border(
                left: _borderSide,
              ),
            ),
            child: Stack(
              alignment: Alignment.bottomLeft,
              children: <Widget>[
                _bgImagePositioned(
                  _minsuBGImageUrl,
                  width: 37,
                ),
                _commonTitle('民宿·客栈'),
              ],
            ),
          ),
        ),
        flex: 23,
      );
    }
    
    Widget _commonTitle(String title) {
      return Center(
        child: Text(
          title,
          style: _titleStyle,
        ),
      );
    }
    
  5. _hotelRow()方法的 // todo: add hotel row items 的下方添加 _secondBGImageStack(), , cmd+s 保存后热更新界面如下:

  6. 添加 platform 视图的布局代码,在 Widget _commonTitle(String title){...函数下方添加如下代码:

    Widget _platformBGImageStack() {
      return Expanded(
        child: FractionallySizedBox(
          widthFactor: 1,
          heightFactor: 1,
          child: Container(
            decoration: BoxDecoration(
              border: Border(
                left: _borderSide,
              ),
              gradient: LinearGradient(colors: _platformColors),
            ),
            child: Stack(
              alignment: Alignment.bottomRight,
              children: <Widget>[
                _bgImagePositioned(_platformBGImage, width: 86),
                _platformTitle('机票/火车票+酒店 '),
                // todo: add platform tag
              ],
            ),
          ),
        ),
        flex: 46,
      );
    }
    
    Widget _platformTitle(String title) {
      return Center(
        child: Text(
          title,
          style: _platformStyle,
        ),
      );
    }
    

    _hotelRow()方法的 // todo: add hotel row items 下方添加

    _platformBGImageStack(),
    

    cmd+s保存并热跟新后界面如下:

  7. 实现方便又便宜的布局,在 Widget _platformTitle(String title) {...函数的下方添加如下代码

    Widget _platformTagTilte(String title) {
      return Center(
        child: Padding(
          padding: EdgeInsets.only(
            bottom: 32,
            left: 38,
          ),
          child: Container(
            decoration: BoxDecoration(
              color: Color(0xfff54c45),
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(7),
                topRight: Radius.circular(7),
                bottomRight: Radius.circular(7),
              ),
            ),
            padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
            child: Text(
              title,
              style: TextStyle(
                color: Color(0xffffffff),
                fontSize: 12,
                fontWeight: FontWeight.w600,
              ),
            ),
          ),
        ),
      );
    }
    

    然后将 // todo: add platform tag 替换为 _platformTagTilte('方便又便宜'), 随后 cmd+s保存并热跟新后界面效果如下:

至此 hotel 行的布局全部完成🎉

# 完成 flightRow 和 travelRow

前面我们已经封装好了 _firstBGimageStack_secondBGImageStack 函数,这里我们给他们添加必要的参数就能实现背景图和标题的更换,现在开始动手吧:

  1. 将备注 // todo: add imageUrl, imgWidth,title.Widget _firstBGimageStack(){正行代码,替换为如下:

    Widget _firstBGimageStack({
      @required String imageUrl,
      double imgWidth = 73,
      String title,
    }) {
    

    并将其内部的 _hotelBGImageUrl 替换为传入的 imageUrl, 37 替换为传入的 imgWidth, 酒店替换为传入的 title, 删除 // todo: add imageUrl, imgWidth,title. 备注;

  2. 1 中的操作将备注 // todo: add imageUrl, imgWidth,title.Widget _secondBGImageStack() {正行代码,替换为如下:

    Widget _secondBGImageStack({
      @required String imageUrl,
      double imgWidth = 37,
      String title,
    }) {
    

    并将其内部的 _minsuBGImageUrl 替换为传入的 imageUrl, 73 替换为传入的 imgWidth, 民宿·客栈替换为传入的 title,删除 // todo: add imageUrl, imgWidth,title. 备注;

  3. _hotelRow 函数内部中调用上述_firstBGimageStack(),_secondBGImageStack()传入相应参数,修改如下

    _firstBGimageStack(
      imageUrl: _hotelBGImageUrl,
      title: '酒店',
    ),
    _secondBGImageStack(
      imageUrl: _minsuBGImageUrl,
      title: '民宿·客栈',
    ),
    

    并删除 // todo: add hotel row items 的备注,然后 cmd+s保存并热更新后界面应该保持不变;

  4. 添加无背景图的items布局

    Widget _noBGImageStack({@required String title}) {
      return Expanded(
        child: FractionallySizedBox(
          widthFactor: 1,
          heightFactor: 1,
          child: Container(
            decoration: BoxDecoration(
              border: Border(
                left: _borderSide,
              ),
            ),
            child: _commonTitle(title),
          ),
        ),
        flex: 23,
      );
    }
    
    Widget _commonTitle(String title) {
      return Center(
        child: Text(
          title,
          style: _titleStyle,
        ),
      );
    }
    
  5. 开始替换 _flightRow() 中的 // todo: add flight row 为如下代码;

    child: Row(
      children: <Widget>[
        _firstBGimageStack(
          imageUrl: _flightBGImageUrl,
          imgWidth: 79,
          title: '飞机',
        ),
        _secondBGImageStack(
          imageUrl: _trainBGImage,
          imgWidth: 37,
          title: '火车票',
        ),
        _noBGImageStack(title: '汽车·船票'),
        _noBGImageStack(title: '专车·租车'),
      ],
    ),
    

    然后 cmd+s 保存并热更新后界面如下:

  6. 同样替换 _travelRow 中的 // todo: add travel row 为如下代码:

    child: Row(
      children: <Widget>[
        _firstBGimageStack(
          imageUrl: _tripBGImage,
          imgWidth: 93,
          title: '旅游',
        ),
        _secondBGImageStack(
          imageUrl: _dingzhiBGImage,
          imgWidth: 61,
          title: '高铁游',
        ),
        _noBGImageStack(title: '邮轮游'),
        _noBGImageStack(title: '定制游'),
      ],
    ),
    

    然后 cmd+s 保存

至此,本文章全部代码结束,感谢您的阅读,同时希望您能跟着自己动手亲自试验一下;

原文地址:Flutter实现携程GirdNav布局

附上deom地址