Разработка прототипа Flutter для целевой страницы
Первоначально опубликовано 3 июня 2019 г.
Этот пост о том, как спроектировать целевую страницу для гипотетического мобильного и веб-приложения, чтобы ресурсы Flutter сказали «Flutter-to-Fly!». Этот пост будет состоять из двух разделов: 1. Разработка и реализация целевой страницы для платформы Android/iOS. 2. Поскольку веб-реализация Flutter на данный момент находится в стадии технического предварительного просмотра, я покажу, как веб-версия той же целевой страницы может быть реализована для Интернета.
Ознакомьтесь с сопутствующим видеоруководством Часть — 1
Ознакомьтесь с сопутствующим видеоруководством Часть 2
Часть 1: Полетная целевая страница для Интернета
Примечание. На данный момент (3 июня 2019 г.) на самом деле не существует ни одного базового решения для кроссплатформенного Flutter. Код веб-приложения использует определенные веб-библиотеки. Плагины, используемые в нативных приложениях флаттера, нельзя использовать в веб-приложениях. На данный момент рекомендуется создать ветку git для размещения кода веб-приложения, пока веб не выйдет из технического предварительного просмотра и экспериментов.
Настраивать:
- Создайте проект Flutter в Android Studio.
- Создайте ветку git
web
- Копировать
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,
)
],
),
),
),
),
),
);
}
}
Окончательная целевая страница выглядит так:
Следующий пост: В следующем посте я напишу о том, как сделать эту страницу адаптивной.
Часть 2: Целевая страница Flutter-to-fly для платформы Native
Я хочу показать вам, как этот код можно преобразовать в нативный, а также собрать и запустить на платформах Android и iOS. Для начала нам нужно создать отдельную ветку и адаптировать ее pubspec.yaml
для родного флаттера. Помните, что на данный момент вы можете использовать любые плагины в нативном коде, но не в веб-варианте. Поэтому имеет смысл сначала создать веб-приложение, а затем адаптировать его на нативной платформе. Как я упоминал ранее, вам нужно будет заменить flutter_web
к flutter
пакеты. Примечание. Возможно, вам потребуется обновить пакеты в собственной среде. Не забудьте обновить активы в соответствующем месте для родного Flutter.
Я создал ветку с именем native
поиграть на платформах Android и iOS. На данный момент я вижу несколько проблем с размерами, поскольку макет предназначен для просмотра на большом экране. В следующем посте я объясню, как мы можем сделать его адаптивным к различным форм-факторам.
А пока продолжайте порхать!
Репозиторий исходного кода: Исходный код для сеть
Исходный код для Родной
Ссылки/Кредиты:
- Миграция в Интернет
- Я адаптировал дизайн целевой страницы гипотетического приложения «Flutter-to-fly» из этот дриблинг дизайн
- Адаптированный этот пример веб-приложения на собственные платформы Flutter, чтобы продемонстрировать кроссплатформенную поддержку Flutter.
Удачной готовки с Flutter
Понравилась статья? Не нашли интересующую вас тему? Пожалуйста, оставьте комментарии или напишите мне о темах, которые вы хотели бы, чтобы я написал