这是我参与11月更文应战的第5天,活动详情检查:2021最终一次更文应战

发现页面完成

Flutter 仿写微信发现、我的页面

这儿咱们模仿微信的发现页面用 Flutter 类完成这页面的简单布局及每个 cell 的点击效果及点击每条 cell 之后跳转到一个新的页面。这儿咱们分几步分别来完成这些功用。

自定义 cell

Flutter 仿写微信发现、我的页面

针对 cell 的布局咱们能够分为两部分,左面跟右边,左面是主图片加标题,右边是子标题、 子图片加箭头。主图片称号、主标题、子标题、子图片称号这些都能够由于 cell 初始化的时分由外部传进来。这儿主图片、标题跟箭头是固定的每个 cell 都有的,子标题、 子图片是可选的。针对 cell 布局的代码如下。

  String title;
  String imageName;
  String subTitle;
  String subImageName;
  DiscoverCell(this.title, this.imageName, this.subTitle, this.subImageName);
Container(
        color: _currentColor,
        height: 55,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            // left
            Container(
              padding: EdgeInsets.all(10),
              child: Row(
                children: [
                  // 图标
                  Image(image: AssetImage(widget.imageName), width: 20,),
                  // 空隙
                  SizedBox(width: 15,),
                  // Title
                  Text(widget.title),
                ],
              ),
            ),
            // right
            Container(
              padding: EdgeInsets.all(10),
              child: Row(
                children: [
                  // subTitle
                  widget.subTitle != null ? Text(widget.subTitle) : Text(''),
                  // subImage
                  widget.subImageName.length > 0 ? Image.asset(widget.subImageName, width: 15,) : Container(),
                  // 箭头
                  Image(image: AssetImage('images/icon_right.png'), width: 15,)
                ],
              ),
            ),
          ],
        ),
      )

列表布局

class _DiscoverPageState extends State<DiscoverPage> {
  Color _themColor = Color.fromRGBO(230, 230, 230, 1.0);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: _themColor,
        // 安卓里面用到,切 app 的时分显示
        centerTitle: true,
        title: Text('发现'),
        elevation: 0.0,
      ),
      body: Container(
        height: 800,
        color: _themColor,
        child: ListView(
          children: [
            DiscoverCell('朋友圈', 'images/朋友圈.png', '', ''),
            SizedBox(height: 10,),
            DiscoverCell('扫一扫', 'images/扫一扫2.png', '', ''),
            //分割线
            Row(
              children: [
                // 左面线条
                Container(width: 50, height: 0.5, color: Colors.white,),
                // 右边线条
                Container(height: 0.5, color: Colors.grey,)
              ],
            ),
            DiscoverCell('摇一摇', 'images/摇一摇.png', '', ''),
            SizedBox(height: 10,),
            DiscoverCell('看一看', 'images/看一看icon.png', '', ''),
            //分割线
            Row(
              children: [
                // 左面线条
                Container(width: 50, height: 0.5, color: Colors.white,),
                // 右边线条
                Container(height: 0.5, color: Colors.grey,)
              ],
            ),
            DiscoverCell('搜一搜', 'images/搜一搜.png', '', ''),
            SizedBox(height: 10,),
            DiscoverCell('邻近的人', 'images/邻近的人icon.png', '', ''),
            SizedBox(height: 10,),
            DiscoverCell('购物', 'images/购物.png', '双十一限时特价', 'images/badge.png'),
            Row(
              children: [
                // 左面线条
                Container(width: 50, height: 0.5, color: Colors.white,),
                // 右边线条
                Container(height: 0.5, color: Colors.grey,)
              ],
            ),
            DiscoverCell('游戏', 'images/游戏.png', '', ''),
            SizedBox(height: 10,),
            DiscoverCell('小程序', 'images/小程序.png', '', ''),
          ],
        ),
      )
    );
  }
}

针对列表的布局咱们用的是 ListView,在 children 里面按次序增加每条 cell 数据,这儿每组之间的间隔咱们用 SizedBoxcell 上的下划线咱们用 Row 来完成,分为左面线条跟右边线条。

cell 点击跳转

Flutter 仿写微信发现、我的页面

return GestureDetector(
      // cell 手势点击
      onTap: (){
        Navigator.of(context).push(
            MaterialPageRoute(builder:
                (BuildContext context) => DiscoverChildPage(widget.title)
            )
        );

这儿咱们定义一个新的页面 DiscoverChildPage 标题由 cell 点击的时分传入。在 cell 中咱们增加点击办法,然后 push 到一个新的页面。

cell 增加点击状况

GestureDetector(
      // cell 手势点击
      onTap: (){
        Navigator.of(context).push(
            MaterialPageRoute(builder:
                (BuildContext context) => DiscoverChildPage(widget.title)
            )
        );
        setState(() {
          _currentColor = Colors.white;
        });
      },
      // cell 手势点击下去
      onTapDown: (TapDownDetails details){
        setState(() {
          _currentColor = Colors.grey;
        });
      },
      // cell 手势点击撤销
      onTapCancel: (){
        setState(() {
          _currentColor = Colors.white;
        });
      },
      child: Container(
        color: _currentColor,
      ),
    );

cell 加上点击状况的话就需求继承于有状况的 Widget,然后在不同的点击状况下设置不同的颜色,然后调用 setState 办法。由于调用 setState 办法的时分会从头构建 widget,所以针对复杂的控件的时分咱们只让需求改变状况的子控件继承于 StatefulWidget,把需求改变的部分抽取出来。咱们这儿由于 cell 整体的子控件也不多,所以咱们就直接让 cell 继承于 StatefulWidget 。也是为了偷下懒。

我的页面完成

Flutter 仿写微信发现、我的页面

我的页面首要咱们能够分为两大块,列表跟相机,这儿咱们采用 Stack 部件来布局。其中列表部分又能够分为两大块头部跟底部 cell 部分。按照这种布局思路咱们的代码如下。

class _MinePageState extends State<MinePage> {
  Widget headerWidget() {
    return Container(
      height: 200,
      color: Colors.white,
      child: Container(
        margin: EdgeInsets.only(top: 90, bottom: 20, left: 16, right: 10),
        child: Row(
          children: [
            // 头像
            Container(
              width: 70,
              height: 70,
              // 设置圆角属性
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                image: DecorationImage(
                    image: AssetImage('images/ChenXi.JPG')
                )
              ),
            ),
            // 右边部分
            Expanded(child: Container(
              padding: EdgeInsets.only(left: 10, top: 8, right: 10),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // 昵称
                  Container(
                    height: 35,
                    child: Text('Chenxi', style: TextStyle(fontSize: 25, color: Colors.black87),)
                  ),
                  // 微信号加箭头
                  Container(
                    height: 35,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text('微信号:CX123', style: TextStyle(fontSize: 17, color: Colors.grey),),
                        Image(image: AssetImage('images/icon_right.png'), width: 15,)
                      ],
                    ),
                  ),
                ],
              ),
            )),
          ],
        ),
      ),
    );
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Color.fromRGBO(230, 230, 230, 1.0),
        child: Stack(
          children: [
            // 列表
            Container(
              child: MediaQuery.removePadding(
                  removeTop: true,
                  context: context,
                  child: ListView(
                children: [
                  // 头部
                  headerWidget(),
                  // 列表
                  SizedBox(height: 10,),
                  DiscoverCell('付出', 'images/微信 付出.png', '', ''),
                  SizedBox(height: 10,),
                  DiscoverCell('保藏', 'images/微信保藏.png', '', ''),
                  //分割线
                  Row(
                    children: [
                      // 左面线条
                      Container(width: 50, height: 0.5, color: Colors.white,),
                      // 右边线条
                      Container(height: 0.5, color: Colors.grey,)
                    ],
                  ),
                  DiscoverCell('朋友圈', 'images/微信相册.png', '', ''),
                  //分割线
                  Row(
                    children: [
                      // 左面线条
                      Container(width: 50, height: 0.5, color: Colors.white,),
                      // 右边线条
                      Container(height: 0.5, color: Colors.grey,)
                    ],
                  ),
                  DiscoverCell('卡包', 'images/微信卡包.png', '', ''),
                  //分割线
                  Row(
                    children: [
                      // 左面线条
                      Container(width: 50, height: 0.5, color: Colors.white,),
                      // 右边线条
                      Container(height: 0.5, color: Colors.grey,)
                    ],
                  ),
                  DiscoverCell('表情', 'images/微信表情.png', '', ''),
                  SizedBox(height: 10,),
                  DiscoverCell('设置', 'images/微信设置.png', '', ''),
                ],
              )
              ),
            ),
            // 相机
            Container(
              margin: EdgeInsets.only(right: 10, top: 25),
              height: 25,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Image(image: AssetImage('images/相机.png')),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

总结:其实完成这些布局的方法有许多,如果需求鉴定哪种布局方法更好的话,咱们遵从页面复杂度最低的布局方法总归是没有错的。