Вызов Flutter: WhatsApp

Сегодня мы предпримем попытку воссоздать UI главного экрана приложения Whatsapp под Android с помощью Flutter.

Основное внимание будет уделено именно UI, а не реализации функционала обмена сообщениями.

Если вы только начинаете разрабатывать на Flutter, обратите внимание на статью Создание первого приложения Flutter и продолжение.

Приступим

Главный экран WhatsApp состоит из:

  1. AppBar с кнопками поиска и меню
  2. Четырёх вкладок внизу AppBar
  3. Вкладка камеры для создания фотографии
  4. Многофункциональной FloatingActionButton
  5. Вкладка “Chats” со списком всех бесед
  6. Вкладка “Status” для обзора всех статусов
  7. Вкладка “Calls” с историей звонков

Настройка проекта

Создайте проект Flutter  именем whatsapp_ui, удалите весь код кроме кода, отрисовывающего пустой экран с верхней панелью:

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>[
            
          ],
        ),
      ),
    );
  }
}

Панель 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,
),

И получим:

Вызов Flutter: WhatsApp

Вкладки / табы

Вкладки реализуются как расширение AppBar и Flutter позволяет легко создать их.

У AppBar есть поле “bottom”, в котором и будут наши вкладки:

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;

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

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

}

Укажем контроллер  полю “controller” в TabBar

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"),
  ],
),
Вызов Flutter: WhatsApp

Перед тем, как перейти на реализацию страниц, добавим страницы, которые будут привязаны к вкладкам. Переделаем существующий код “body” в Scaffold таким образом:

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

Здесь в children перечислены страницы, соотвествующие вкладкам. И в данный момент страница представлена виджетом Text.

Floating Action Button

Действие Плавающей кнопки меняется в зависимости от того, с какой страницы вызвана.

Добавим FloatingActionButton в Scaffold.

floatingActionButton: FloatingActionButton(
  onPressed: () {
  },
  child: fabIcon,
  backgroundColor: whatsAppGreenLight,
),

Поле “fabIcon” хранит картинку, которая будет представлена пользователю в зависимости от выбранного экрана.

Для отслеживания смены вкладки, добавим listener в 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;
      }
    });
  });
Вызов Flutter: WhatsApp

Продолжим,

Экран чата

Экран чата (Chat Screen) включает список сообщений, которые необходимо вывести. Для создания списка сообщений используем ListView.builder().

Вот так будет выглядеть элемент списка чатов.

Вызов Flutter: WhatsApp

Этот виджет представляет собой строку с картинкой и ещё одну строку.

Внутри второй строки располагается колонка, включающая одну строку и текстовый виджет.

В строке указано название и дата сообщения.

Создадим модель сообщения чата (Chat Item Model) как класс для хранения деталей элемента списка.

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(),
    ],
  );
},

Результат после создания списка:

Вызов Flutter: WhatsApp

Таким же образом мы можем создавать другие вкладки и на других экранах. Полный пример выложен на GitHub.

Ссылка на GitHub: https://github.com/deven98/WhatsappFlutter

Перевод статьи «Flutter Challenge: WhatsApp»

Подписывайтесь на новости Flutter! https://t.me/flutterdaily

Вызов Flutter: WhatsApp

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Пишите: @ighar. Buy me a coffee, please :).

Leave a Comment

Чтобы не пропустить новые статьи, оставь свой Email

Поздравляем вы подписаны на новости ТехноДжем!

TВо время отправки данных произошла ошибка. Попробуйте ещё раз

Оставляя свою почту