Flutter Challenges 是一项尝试利用 Flutter 重新创建特定的应用程序 UI 或设计的挑战。 此次挑战将尝试 Whatsapp Android 应用程序的主界面。 请注意将重点放在 UI 上而不是实际获取消息。

开始

WhatsApp 的主界面包括:

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

项目设置

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

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 具有应用程序的标题, 以及两个操作: 搜索和菜单。

将其添加到 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,
),

代码结果如下:

现在继续

The Tabs

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

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

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 链接 : https://github.com/deven98/WhatsappFlutter

感谢您阅读此 Flutter 挑战。 随意提及您可能想要在 Flutter 中重新创建的任何应用程序。 如果你喜欢它, 一定要留下掌声, 再见。

不要忘了: The Medium App in Flutter

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


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