[译] 挑战 Flutter 之 WhatsApp

Flutter Challenges 是一项尝试利用 Flutter 从新建立特定的应用程序UI或设计的挑战。前端

这次挑战将尝试 Whatsapp Android 应用程序的主界面。请注意将重点放在 UI 上而不是实际获取消息。android

开始

WhatsApp 的主界面包括:ios

  1. 一个带有搜索操做和菜单的 AppBar
  2. 在 AppBar 的底部有四个标签
  3. 一个用于拍照的相机标签
  4. 一个用于多种用途的 FloatingActionButton
  5. 一个“聊天”标签可查看全部对话
  6. 一个“状态”选项卡可查看全部状态
  7. 一个“打电话”选项卡可查看全部的通话记录

项目设置

让咱们建立一个名为 whatsapp_ui 的 Flutter 项目并删除全部默认代码,只留下一个带有默认应用栏的空白屏幕。git

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("WhatsApp"),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            
          ],
        ),
      ),
    );
  }
}
复制代码

The AppBar

AppBar 具备应用程序的标题,以及两个操做:搜索和菜单。github

将其添加到 AppBar 中,后端

appBar: new AppBar(
  title: new Text("WhatsApp", style: TextStyle(color: Colors.white, fontSize: 22.0, fontWeight: FontWeight.w600),),
  actions: <Widget>[
    Padding(
      padding: const EdgeInsets.only(right: 20.0),
      child: Icon(Icons.search),
    ),
    Padding(
      padding: const EdgeInsets.only(right: 16.0),
      child: Icon(Icons.more_vert),
    ),
  ],
  backgroundColor: whatsAppGreen,
),
复制代码

代码结果以下:bash

如今继续app

The Tabs

tabs(选项卡)是 AppBar 的简单扩展,Flutter 使它们很是容易实现。less

AppBar 有一个“底部”字段,用于保存咱们的标签:ide

bottom: TabBar(
  tabs: [
    Tab(icon: Icon(Icons.camera_alt),),
    Tab(child: Text("CHATS"),),
    Tab(child: Text("STATUS",)),
    Tab(child: Text("CALLS",)),
  ], indicatorColor: Colors.white,
),
复制代码

此外,咱们须要一个 TabController 来实现这一点。

建立一个新的 TabController。

TabController tabController;

@override
void initState() {
  // TODO: implement initState
  super.initState();

  tabController = TabController(vsync: this, length: 4);

}
复制代码

如今将该控制器添加到 TabBar 的 “controller” 字段中。

bottom: TabBar(
  tabs: [
    Tab(icon: Icon(Icons.camera_alt),),
    Tab(child: Text("CHATS"),),
    Tab(child: Text("STATUS",)),
    Tab(child: Text("CALLS",)),
  ], indicatorColor: Colors.white,
  controller: tabController,
),
复制代码

而对于 TabBarView

body: TabBarView(
  controller: tabController,
  children: [
    Icon(Icons.camera_alt),
    Text("Chat Screen"),
    Text("Status Screen"),
    Text("Call Screen"),
  ],
),
复制代码

如今,在转到各个页面以前,咱们将添加选项卡所表明的页面。用如下方法切换脚手架的现有“正文”代码:

body: TabBarView(
  children: [
    Icon(Icons.camera_alt),
    Text("Chat Screen"),
    Text("Status Screen"),
    Text("Call Screen"),
  ],
),
复制代码

子项表明选项卡所用的页面。如今整个页面都是一个 Text 小部件。

悬浮按钮

Floating Action Button 根据屏幕上的页面而变化。

首先在脚手架中添加一个 FloatingActionButton。

floatingActionButton: FloatingActionButton(
  onPressed: () {
  },
  child: fabIcon,
  backgroundColor: whatsAppGreenLight,
),
复制代码

“fabIcon” 字段只存储要显示的图标,由于咱们须要根据显示的屏幕更改显示的图标。

要监听选项卡选定的更改,须要给 TabController 添加一个监听器。

tabController = TabController(vsync: this, length: 4)
  ..addListener(() {
    
  });
复制代码

如今,当标签控制器实现页面已更改时,请更改 FAB 图标。

tabController = TabController(vsync: this, length: 4)
  ..addListener(() {
    setState(() {
      switch(tabController.index) {
        case 0:
          break;
        case 1:
          fabIcon = Icons.message;
          break;
        case 2:
          fabIcon = Icons.camera_enhance;
          break;
        case 3:
          fabIcon = Icons.call;
          break;
      }
    });
  });
复制代码

继续,

聊天界面

聊天屏幕有一个咱们须要显示的消息列表。要建立消息列表,咱们使用 ListView.builder() 并构造咱们的项目。

让咱们来看看聊天界面的列表项。

最外面的小部件是一行图标和另外一行

第二行内部是一列,包含一行和一个文本小部件。

该行具备标题和消息日期。

让咱们构建一个聊天项模型做为用于存储列表项详细信息的类。

class ChatItemModel {
  
  String name;
  String mostRecentMessage;
  String messageDate;
  
  ChatItemModel(this.name, this.mostRecentMessage, this.messageDate);
  
}
复制代码

如今,为简洁起见,我省略了添加我的资料图片。

itemBuilder: (context, position) {
  ChatItemModel chatItem = ChatHelper.getChatItem(position);

  return Column(
    children: <Widget>[
      Padding(
        padding: const EdgeInsets.all(8.0),
        child: Row(
          children: <Widget>[
            Icon(
              Icons.account_circle,
              size: 64.0,
            ),
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Row(
                      mainAxisAlignment:
                          MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          chatItem.name,
                          style: TextStyle(
                              fontWeight: FontWeight.w500,
                              fontSize: 20.0),
                        ),
                        Text(
                          chatItem.messageDate,
                          style: TextStyle(color: Colors.black45),
                        ),
                      ],
                    ),
                    Padding(
                      padding: const EdgeInsets.only(top: 2.0),
                      child: Text(
                        chatItem.mostRecentMessage,
                        style: TextStyle(
                            color: Colors.black45, fontSize: 16.0),
                      ),
                    )
                  ],
                ),
              ),
            )
          ],
        ),
      ),
      Divider(),
    ],
  );
},
复制代码

建立第一个列表后,结果以下:

咱们能够相似地在其余屏幕上的屏幕上建立其余选项卡。完整的示例托管在GitHub上。

GitHub 连接 : github.com/deven98/Wha…

感谢您阅读此 Flutter 挑战。随意说起您可能想要在 Flutter 中从新建立的任何应用程序。若是你喜欢它,必定要留下掌声,再见。

不要忘了:The Medium App in Flutter

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索