Разработка прототипа Flutter для целевой страницы

Первоначально опубликовано 3 июня 2019 г.

Этот пост о том, как спроектировать целевую страницу для гипотетического мобильного и веб-приложения, чтобы ресурсы Flutter сказали «Flutter-to-Fly!». Этот пост будет состоять из двух разделов: 1. Разработка и реализация целевой страницы для платформы Android/iOS. 2. Поскольку веб-реализация Flutter на данный момент находится в стадии технического предварительного просмотра, я покажу, как веб-версия той же целевой страницы может быть реализована для Интернета.

Ознакомьтесь с сопутствующим видеоруководством Часть — 1

Ознакомьтесь с сопутствующим видеоруководством Часть 2

Часть 1: Полетная целевая страница для Интернета

Примечание. На данный момент (3 июня 2019 г.) на самом деле не существует ни одного базового решения для кроссплатформенного Flutter. Код веб-приложения использует определенные веб-библиотеки. Плагины, используемые в нативных приложениях флаттера, нельзя использовать в веб-приложениях. На данный момент рекомендуется создать ветку git для размещения кода веб-приложения, пока веб не выйдет из технического предварительного просмотра и экспериментов.

Настраивать:

  1. Создайте проект Flutter в Android Studio.
  2. Создайте ветку git web
  3. Копировать pubspec.yaml к pubspec.yaml.native для резервного копирования собственных настроек платформы. Нам это понадобится для собственного проекта в другой ветке, скажем master. Я бы оставил собственный код в ветке по умолчанию master.

Настроить pubspec.yaml Адаптировать pubspec.yaml для Интернета, как описано в эта ссылка.

Вот как pubspec.yaml для веб-приложения будет выглядеть так:

name: landingpage
description: Cross platform sample landing page implemented in Flutter

version: 1.0.0+1

dependencies:
  flutter_web: any

dev_dependencies:
  flutter_web_test: any
  #dependencies to enable the Dart web build system
  build_runner: ^1.2.2
  build_web_compilers: ^1.1.0
  test: ^1.3.4

  ## These overrides tell the package tools to get them from GitHub
dependency_overrides:
  flutter_web:
    git:
      url: 
      path: packages/flutter_web
  flutter_web_ui:
    git:
      url: 
      path: packages/flutter_web_ui
  flutter_web_test:
    git:
      url: 
      path: packages/flutter_web_test

Создавать web каталог: Создать web каталог для размещения точки входа для веб-приложения на корневом уровне (тот же уровень, что и lib каталог). web/index.html а также web/main.dart необходимо добавить, как указано здесь

Создание веб-приложения: перейти в текущий рабочий каталог и получить все зависимости.
Дартс использует webdev построить и запустить проект. Обязательно активируйте webdev перед созданием проекта, как показано ниже. Не забудьте включить его в системный PATH, используя export PATH="$PATH":"$HOME/.pub-cache/bin" после активации.

pub global activate webdev
webdev serve

Веб-приложение начнет работать на локальном хосте с портом 8080.

Примечание. Убедитесь, что вы заменили все package:flutter пакеты с package:flutter_web вариант.

На данный момент мы закончили настройку проекта Flutter, чтобы приступить к созданию веб-приложения. Вы увидите запущенное приложение счетчика по умолчанию, представленное как часть встроенных примеров.

Веб-настройка флаттера

Шаг 1: Очистите предварительно сгенерированный код с помощью Flutter. Делать MyHomePage Stateless виджет. Удалить заголовок, переданный в MyHomePage. Обновите название приложения на Flutter to fly !. Вот как твой main.dart должно выглядеть так:

import 'package:flutter_web/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter to fly !',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return null;
  }

}

Теперь давайте добавим заголовок и тело для целевой страницы. В шапке будет логотип сайта и навигационные ссылки. Тело будет иметь фоновое изображение, текстовое поле для отправки электронных писем, чтобы подписаться на список рассылки для любых обновлений контента.

Во-первых, добавьте линейный градиент на всю страницу, используя два разных оттенка белого (я создал класс MyColors.dart для хранения всех моих пользовательских цветов).

@override
  Widget build(BuildContext context) {
    //Add a container and provide a linear gradient.
    //basically use different shades of same color.
    return Container(
      decoration: BoxDecoration(
          gradient: LinearGradient(colors: [MyColors.white1, MyColors.white2])),
    );
  }

Добавить Scaffold как ребенок Container выше, чтобы удерживать всю страницу, как показано ниже:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //Add a container and provide a linear gradient.
    //basically use different shades of same color.
    return Container(
      decoration: BoxDecoration(
          gradient: LinearGradient(colors: [MyColors.white1, MyColors.white2])),
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: SingleChildScrollView(
          child: Column(
            children: <Widget>[Header(), Body()],
          ),
        ),
      ),
    );
  }
}

SingleChildScrollView будет содержать заголовок и тело страницы. Я создал два класса: Header а также Body чтобы помочь нам с заголовком и основной частью/виджетами.

_Header Widget_Header Раздел/виджет содержит логотип и название сайта слева, а также навигационные ссылки и кнопку входа в систему справа. я буду использовать Padding виджет, содержащий логотип раздела заголовка и ссылки. Логотип заголовка

Ниже приведен фрагмент кода, который отвечает за создание логотипа выше:

//Builds rectangle with circular corners and Text on it and next to it as title
Widget buildLogo() {
  return Row(
    children: <Widget>[
      Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(18),
          gradient: LinearGradient(colors: [MyColors.blue1, MyColors.blue2],
          begin: Alignment.bottomRight, end: Alignment.topLeft),
        ),
        child: Center(
          child: Text(Strings.logoTitle,
          style: TextStyle(fontSize: 30, color: MyColors.white1),),
        ),
      ),
      //give some space between logo box and title
      SizedBox(
        width: 16,
      ),
      Text(Strings.appTitle, style: TextStyle(fontSize: 26),)
    ],
  );
}

Кнопка входа Логотип заголовка

//Builds and decorates login button
Widget buildLoginButton() {
  return Padding(
    padding: EdgeInsets.all(8.0),
    child: InkWell(
      child: Container(
        margin: EdgeInsets.only(left: 20),
        width: 120,
        height: 40,
        decoration: BoxDecoration(
          gradient: LinearGradient(colors: [
            MyColors.blue1, MyColors.blue2
          ],
          begin: Alignment.bottomRight,
          end: Alignment.topLeft),
          borderRadius: BorderRadius.circular(20),
          boxShadow: [
            BoxShadow(
              color: MyColors.blue3.withOpacity(0.3),
              offset: Offset(0, 8), //Shadow starts at x=0, y=8
              blurRadius: 8
            )
          ]
        ),
        child: Material(
          color: Colors.transparent,
          child: Center(
            child: Text(Strings.loginButton,
            style: TextStyle(
              color: MyColors.white1,
              fontSize: 18,
              letterSpacing: 1
            ),),
          ),
        ),
      ),
    ),
  );
}

_Ссылки навигации заголовка_Теперь добавьте ссылки навигации заголовка непосредственно перед кнопкой входа в систему, созданной выше, чтобы завершить раздел заголовка.

Получить список ссылок, которые будут отображаться в шапке:

//Builds navigation list for header
List<Widget> getLinksListing() {
  var links = ["Home", "Samples", "Videos", "Plugins"];
  return links.map((link) {
    return Padding(
      padding: EdgeInsets.only(left: 18),
      child: Text(
        link,
        style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
      ),
    );
  }).toList();
}

Добавить список ссылок в шапку:

//Builds navigation links at the right top of landing page
Widget buildHeaderLinks() {
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceAround,
    children: getLinksListing()..add(buildLoginButton()),
  );
}

Наконец, создайте виджет заголовка:

@override
Widget build(BuildContext context) {
  return Padding(
    padding: EdgeInsets.symmetric(horizontal: 45, vertical: 38),
    child: buildHeader(),
  );
}

Widget buildHeader() {
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: <Widget>[buildLogo(), buildHeaderLinks()],
  );
}

Вот как заголовок выглядит в этот момент: Веб-настройка флаттера

На данный момент мы закончили с заголовком. Давайте перейдем к разделу тела в Шаге 2.

Шаг 2: Раздел тела состоит из трех компонентов. 1. Фоновое изображение, показывающее флаттер-арт. 2. Приветственный текст. 3. Подписка на список рассылки: текстовое поле, позволяющее пользователю ввести свои адреса электронной почты для подписки на информационный бюллетень.

Добавление фонового изображения: Все изображения помещаются внутрь web/assets каталог. Фоновое изображение добавляется с выравниванием по правому краю страницы.

//Adds background Image
Widget addBackground() {
  return FractionallySizedBox(
    alignment: Alignment.centerRight, //to keep images aligned to right
    widthFactor: .6, //covers about 60% of the screen width
    child: Image.network(backgroundImage, scale: .85,),
  );
}

Давайте поработаем над заголовком приветственного текста.

Добавление приветственного текста: на этом этапе я добавил текст приветствия, и он выглядит следующим образом: Веб-настройка флаттера

//Adds welcome text
Widget addWelcomeText() {
  return FractionallySizedBox(
    alignment: Alignment.centerLeft, //text aligned to left side
    widthFactor: .6, //covers about half of the screen
    child: Padding(
      padding: EdgeInsets.only(left: 48),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            Strings.hello,
            style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 60,
              color: MyColors.blue4,
            ),
          ),
          RichText(
            text: TextSpan(
              text: Strings.welcomeTo,
              style: TextStyle(
                fontSize: 60,
                color: MyColors.blue4
              ),
              children: [
                TextSpan(
                  text: Strings.ftf,
                  style: TextStyle(
                    fontSize: 60,
                    fontWeight: FontWeight.bold,
                    color: Colors.black54
                  )
                )
              ]
            ),
          ),
          Padding(
            padding: EdgeInsets.only(left: 12.0, top: 20),
            child: Text(Strings.subscribeText),
          ),
          SizedBox(height: 40,), //Give some spacing
          EmailBox() //Alert : this will be added after next step
        ],
      ),
    ),
  );
}

Давайте поработаем над третьей частью основного раздела: пользователи вводят свои адреса электронной почты в текстовое поле, чтобы подписаться на сайт.

Подписка на рассылку: Этот компонент состоит из двух частей. Одним из них является текстовое поле для ввода адресов электронной почты пользователем. Назовем этот виджет EmailBox. Еще одна кнопка, на которую нужно нажать, чтобы подписаться. Я называю этот виджет как SubscribeButton

Вот как выглядит код EmailBox:

class EmailBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(left: 4.0, right: 74, top: 10, bottom: 40),
      child: Container(
        height: 60,
        decoration: BoxDecoration(
            color: MyColors.white1,
            borderRadius: BorderRadius.circular(20),
            boxShadow: [
              BoxShadow(
                  color: Colors.black12, offset: Offset(0, 8), blurRadius: 8)
            ]),
        child: Padding(
          padding: EdgeInsets.symmetric(horizontal: 20),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Expanded(
                flex: 8,
                child: TextField(
                  decoration: InputDecoration(
                      border: InputBorder.none, hintText: Strings.email_hint),
                ),
              ),
              Expanded(
                flex: 2,
                child: SubscribeButton(),
              )
            ],
          ),
        ),
      ),
    );
  }
}

SubscribeButton вызывается из EmailBox. Виджет «Кнопка подписки» выглядит следующим образом:

import 'package:flutter_web/material.dart';
import 'package:landingpage/utils/myColors.dart';
import 'package:landingpage/utils/strings.dart';

class SubscribeButton extends StatelessWidget {
  var emailImage = "assets/email.png";

  @override
  Widget build(BuildContext context) {
    return InkWell(
      child: Container(
        height: 40,
        decoration: BoxDecoration(
            gradient: LinearGradient(
                colors: [MyColors.blue1, MyColors.blue2],
                begin: Alignment.bottomRight,
                end: Alignment.topLeft),
            borderRadius: BorderRadius.circular(20.0),
            boxShadow: [
              BoxShadow(
                  color: MyColors.blue3.withOpacity(.3),
                  offset: Offset(0, 8),
                  blurRadius: 8.0)
            ]),
        child: Material(
          color: Colors.transparent,
          child: InkWell(
            onTap: () {}, //TODO
            child: Center(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    Strings.subscribeButton,
                    style: TextStyle(
                        color: MyColors.white1, fontSize: 16, letterSpacing: 1),
                  ),
                  SizedBox(
                    width: 8,
                  ),
                  Image.network(
                    emailImage,
                    color: MyColors.white1,
                    width: 20,
                    height: 20,
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Окончательная целевая страница выглядит так: Flutter to fly целевая страница

Следующий пост: В следующем посте я напишу о том, как сделать эту страницу адаптивной.

Часть 2: Целевая страница Flutter-to-fly для платформы Native

Я хочу показать вам, как этот код можно преобразовать в нативный, а также собрать и запустить на платформах Android и iOS. Для начала нам нужно создать отдельную ветку и адаптировать ее pubspec.yaml для родного флаттера. Помните, что на данный момент вы можете использовать любые плагины в нативном коде, но не в веб-варианте. Поэтому имеет смысл сначала создать веб-приложение, а затем адаптировать его на нативной платформе. Как я упоминал ранее, вам нужно будет заменить flutter_web к flutter пакеты. Примечание. Возможно, вам потребуется обновить пакеты в собственной среде. Не забудьте обновить активы в соответствующем месте для родного Flutter.

Я создал ветку с именем native поиграть на платформах Android и iOS. На данный момент я вижу несколько проблем с размерами, поскольку макет предназначен для просмотра на большом экране. В следующем посте я объясню, как мы можем сделать его адаптивным к различным форм-факторам.

А пока продолжайте порхать!

Репозиторий исходного кода: Исходный код для сеть

Исходный код для Родной

Ссылки/Кредиты:

  1. Миграция в Интернет
  2. Я адаптировал дизайн целевой страницы гипотетического приложения «Flutter-to-fly» из этот дриблинг дизайн
  3. Адаптированный этот пример веб-приложения на собственные платформы Flutter, чтобы продемонстрировать кроссплатформенную поддержку Flutter.

Удачной готовки с Flutter 😃

Понравилась статья? Не нашли интересующую вас тему? Пожалуйста, оставьте комментарии или напишите мне о темах, которые вы хотели бы, чтобы я написал Кстати, я люблю и кексы, и кофе :)

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *