company_banner

[По докам] Flutter. Часть 4. Для веб-разработчиков

    Начинаем новую неделю с очередной интерпретации официальной документации Flutter в формате «вопрос-ответ». 4-я часть освещает в сравнительном стиле Flutter для веб-разработчиков. Она целиком посвящена вёрстке и вышла не такой объёмной, как предыдущие. Традиционно рекомендую всем интересующимся Flutter веб-разработчикам заглянуть под кат, чтобы понять, стоит ли пробовать этот фреймворк и сколько усилий это займёт.



    Если информации здесь будет недостаточно или у вас есть опыт в нативной разработке под конкретную платформу, то рекомендую заглянуть в другие части:

    Flutter. Часть 1. Для Android-разработчиков
    Flutter. Часть 2. Для iOS-разработчиков
    Flutter. Часть 3. Для React Native-разработчиков
    Flutter. Часть 4. Для веб-разработчиков
    Flutter. Часть 5. Для Xamarin.Forms-разработчиков

    Содержание:


    1. Базовая вёрстка

    2. Позиции и размеры

    3. Форма

    4. Текст


    Базовая вёрстка


    Вопрос:


    Как стилизовать и выравнивать текст?

    Ответ:


    С помощью TextStyle.

    Пример:


    HTML/CSS

    <div class="greybox">
        Lorem ipsum
    </div>
    
    .greybox {
          background-color: #e0e0e0; /* grey 300 */
          width: 320px;
          height: 240px;
          font: 900 24px Georgia;
        }
    

    Flutter

    var container = Container( // grey box
      child: Text(
        "Lorem ipsum",
        style: TextStyle(
          fontSize: 24,
          fontWeight: FontWeight.w900,
          fontFamily: "Georgia",
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос:


    Как устанавливается цвет фона?

    Ответ


    С помощью класса BoxDecoration.

    Отличия


    Свойство background-color в CSS отвечает только за цвет фона. BoxDecoration отвечает за более широкий спектр свойств, например скругление углов, окантовку и т.п.

    Пример


    HTML/CSS

    <div class="greybox">
      Lorem ipsum
    </div>
    
    .greybox {
          background-color: #e0e0e0;  /* grey 300 */
          width: 320px;
          height: 240px;
          font: 900 24px Roboto;
        }

    Flutter
    var container = Container( // grey box
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
      ),
      width: 320,
      height: 240,
      decoration: BoxDecoration(
        color: Colors.grey[300],
      ),
    );

    Вопрос:


    Как центрировать компоненты?

    Ответ


    С помощью виджета Center.

    Пример


    HTML/CSS

    <div class="greybox">
      Lorem ipsum
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center; 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Text(
          "Lorem ipsum",
          style: bold24Roboto,
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос:


    Как установить ширину контейнера?

    Ответ


    С помощью свойства width.

    Отличия


    У виджетов Flutter свойство width фиксировано. Чтобы настроить maxWidth или minWidth, используется виджет BoxConstraints.

    Пример:


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px; 
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      width: 100%;
      max-width: 240px; 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
          ),
          padding: EdgeInsets.all(16),
          width: 240, //max-width is 240
        ),
      ),
      width: 320, 
      height: 240,
      color: Colors.grey[300],
    );

    Позиции и размеры


    Вопрос


    Как устанавливать абсолютную позицию?

    Ответ


    С помощью виджета Positioned внутри виджета Stack.

    Дополнительная информация


    По умолчанию виджеты позиционируются внутри родительских виджетов.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      position: relative; 
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      position: absolute;
      top: 24px;
      left: 24px; 
    }

    Flutter
    var container = Container( // grey box
      child: Stack(
        children: [
          Positioned( // red box
            child: Container(
              child: Text(
                "Lorem ipsum",
                style: bold24Roboto,
              ),
              decoration: BoxDecoration(
                color: Colors.red[400],
              ),
              padding: EdgeInsets.all(16),
            ),
            left: 24,
            top: 24,
          ),
        ],
      ), 
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос


    Как задавать вращение компонентам?

    Ответ


    С помощью виджета Transform.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      transform: rotate(15deg); 
    }

    Flutter
    var container = Container( // gray box
      child: Center(
        child: Transform(
          child: Container( // red box
            child: Text(
              "Lorem ipsum",
              style: bold24Roboto,
              textAlign: TextAlign.center,
            ),
            decoration: BoxDecoration(
              color: Colors.red[400],
            ),
            padding: EdgeInsets.all(16),
          ),
          alignment: Alignment.center,
          transform: Matrix4.identity()
            ..rotateZ(15 * 3.1415927 / 180),
        ), 
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос


    Как скейлить компоненты?

    Ответ


    С помощью виджета Transform.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      transform: scale(1.5); 
    }

    Flutter
    var container = Container( // gray box
      child: Center(
        child: Transform(
          child: Container( // red box
            child: Text(
              "Lorem ipsum",
              style: bold24Roboto,
              textAlign: TextAlign.center,
            ),
            decoration: BoxDecoration(
              color: Colors.red[400],
            ),
            padding: EdgeInsets.all(16),
          ),
          alignment: Alignment.center,
          transform: Matrix4.identity()
            ..scale(1.5),
         ), 
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос


    Как применить градиент?

    Ответ


    С помощью класса BoxDecoration и его свойства gradient.

    Пример


    Вертикальный линейный градиент

    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      padding: 16px;
      color: #ffffff;
      background: linear-gradient(180deg, #ef5350, rgba(0, 0, 0, 0) 80%); 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
          ),
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: const Alignment(0.0, -1.0),
              end: const Alignment(0.0, 0.6),
              colors: <Color>[
                const Color(0xffef5350),
                const Color(0x00ef5350)
              ],
            ),
          ), 
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Горизонтальный линейный градиент

    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      padding: 16px;
      color: #ffffff;
      background: linear-gradient(90deg, #ef5350, rgba(0, 0, 0, 0) 80%); 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
          ),
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: const Alignment(-1.0, 0.0),
              end: const Alignment(0.6, 0.0),
              colors: <Color>[
                const Color(0xffef5350),
                const Color(0x00ef5350)
              ],
            ),
          ), 
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Форма


    Вопрос


    Как скруглять углы?

    Ответ


    С помощью класса BoxDecoration и его свойства borderRadius.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* gray 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      border-radius: 8px; 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red circle
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
            borderRadius: BorderRadius.all(
              const Radius.circular(8),
            ), 
          ),
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос


    Как добавить тень?

    Ответ


    С помощью класса BoxShadow.

    Дополнительная информация


    BoxShadow используется в рамках свойства boxShadow класса BoxDecoration.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8),
                  0 6px 20px rgba(0, 0, 0, 0.5);
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
            boxShadow: [
              BoxShadow (
                color: const Color(0xcc000000),
                offset: Offset(0, 2),
                blurRadius: 4,
              ),
              BoxShadow (
                color: const Color(0x80000000),
                offset: Offset(0, 6),
                blurRadius: 20,
              ),
            ], 
          ),
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      decoration: BoxDecoration(
        color: Colors.grey[300],
      ),
      margin: EdgeInsets.only(bottom: 16),
    );

    Вопрос


    Как делать круглые и эллипсовидные формы?

    Ответ


    С помощью enum-класса BoxShape.

    Дополнительная информация


    BoxShape используется в рамках свойства shape класса BoxDecoration.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redcircle">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* gray 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redcircle {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      text-align: center;
      width: 160px;
      height: 160px;
      border-radius: 50%; 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red circle
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
            textAlign: TextAlign.center, 
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
            shape: BoxShape.circle, 
          ),
          padding: EdgeInsets.all(16),
          width: 160,
          height: 160, 
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Текст


    Вопрос


    Как регулировать расстояние между текстом?

    Ответ


    С помощью класса TextStyle и его свойств letterSpacing и wordSpacing.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      letter-spacing: 4px; 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: Text(
            "Lorem ipsum",
            style: TextStyle(
              color: Colors.white,
              fontSize: 24,
              fontWeight: FontWeight.w900,
              letterSpacing: 4, 
            ),
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
          ),
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос


    Как форматировать часть текста?

    Ответ


    С помощью виджета RichText и класса TextSpan.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem <em>ipsum</em> 
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto; 
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
    }
     .redbox em {
      font: 300 48px Roboto;
      font-style: italic;
    }

    Flutter

    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: RichText(
            text: TextSpan(
              style: bold24Roboto,
              children: <TextSpan>[
                TextSpan(text: "Lorem "),
                TextSpan(
                  text: "ipsum",
                  style: TextStyle(
                    fontWeight: FontWeight.w300,
                    fontStyle: FontStyle.italic,
                    fontSize: 48,
                  ),
                ),
              ],
            ),
          ), 
          decoration: BoxDecoration(
            color: Colors.red[400],
          ),
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    Вопрос


    Как ограничить показ длинного текста?

    Ответ


    С помощью совойств maxLines и overflow виджета Text.

    Пример


    HTML/CSS

    <div class="greybox">
      <div class="redbox">
        Lorem ipsum dolor sit amet, consec etur
      </div>
    </div>
    
    .greybox {
      background-color: #e0e0e0; /* grey 300 */
      width: 320px;
      height: 240px;
      font: 900 24px Roboto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .redbox {
      background-color: #ef5350; /* red 400 */
      padding: 16px;
      color: #ffffff;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap; 
    }

    Flutter
    var container = Container( // grey box
      child: Center(
        child: Container( // red box
          child: Text(
            "Lorem ipsum dolor sit amet, consec etur",
            style: bold24Roboto,
            overflow: TextOverflow.ellipsis,
            maxLines: 1, 
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
          ),
          padding: EdgeInsets.all(16),
        ),
      ),
      width: 320,
      height: 240,
      color: Colors.grey[300],
    );

    В конце декабря 2019 года, с выходом Flutter 1.12, поддержка веба перешла в стадию beta! И это отличная новость, означающая, что в недалёком будущем мы будем всё чаще встречать сайты, написанные на Flutter. Поэтому, если вы всё ещё в раздумьях, рекомендую попробовать этот фреймворк и надеюсь, что моя статья была полезной. А на сегодня у меня всё. Да не сломает Google ваш Chrome!
    FunCorp
    Разработка развлекательных сервисов

    Похожие публикации

    Комментарии 17

      0
      Вопрос следующий — в мобильных приложениях флаттер предназначен для высокоскоростной отрисовки (60+ фпс). Имеют ли веб-страницы сформированные флаттером схожую скорость работы, или браузер не позволяет?
        0
        Насколько мне известно по докам Flutter, они не разделяют перфоманс по платформам и пишут такие значения для всех. Про UI Performance тут.
          0
          Еще рано судить, но при определенном подходе запуск на web будет очень быстрый и при минимальных изменениях. Но тени в списке элементов я пока что убрал) Для полноценного понимания перфоманса надо жадть релиза…
          0
          А во Flutter есть ли другие единицы измерения кроме пикселя, типа "%, vw, vh, em". Есть ли подобие media запросов, в частности для определения высоты устройства?
            0
            1. Кроме пикселя не встречал, скорее всего нет
            2. Есть класс MediaQuery для этих целей.
              0
              Да, как уже ответили, есть только пиксели. Причём они умножаются на pixel ratio, то есть вы работаете не с реальным разрешением экрана. Проценты можно получать из ширины/высоты экрана, но на практике это не нужно. Здесь есть хороший аналог flexbox и это решает многие проблемы с размерами.
              0
              Интересно, а создатели flutter собираются что-то делать с этим обилием скобочек?
              Посмотрите на пример с RichText: как удобно и понятно выглядит CSS и как нужно ломать глаза, читая код Flutter, чтобы сообразить что к чему относится.
                0
                Скорее всего нет, но всё может быть. Для удобного чтения у плагина есть инструменты в IDE, например, Flutter Inspector.
                0

                Я застопорился во флаттере при попытке подружить его с бд.
                Получается, что flutter позволяет писать исключительно фронт, к нему надо поделать какой-то бэк, работающий уже по Json api, который, вроде бы можно написать на том же dart, но на самом деле не очень то, т.к. экосистема пока, кажется, сыровата, и, опять же, я так и не понял, как дешево и сердито подружиться с бд (нашел только библиотеку под postgresql, которая вообще вроде как разработана для dart angular).
                можете как-то осветить эти вопросы, да и вообще хоть сколько-нибудь осмысленную модель full-stack разработки в экосистеме dart/flutter?


                dart сам по себе понравился невероятно, эдакий элегантный статический python. Но в жизни применить так и не получилось

                  0

                  [deleted]

                    +1
                    Дешево и сердито можно попробовать SQL-based базу Moor. Достаточно популярная либа. К сожалению, в full-stack пока не копал, не смогу на это ответить.
                      +2
                      Вам скорее всего надо для себя понять, что для вас база данных. Если вам достаточно хранить конфигурацию приложения и токены, то подойдет LocalStorage. Это обычное key:value хранилище.

                      Если что-то поболее, к примеру какие нибудь записки, чек листы итд, что не подразумевает больших данных и они служат только для пользователя и не для шаринга другим пользователям. Смотрим на SQLite, SQLCipher. Я больше чем на 100% что для таких вещей SQLite просто за глаза.

                      Ну и если подразумевается работа с данными у пользователя, не только в приложении, а и, к примеру, из веб странички. Или же это лента новостей или общий чат для пользователей или общие данные для покупателя/продавца. Здесь вам уже понадобится отдельный сервер, логика приложения и база или может быть базы данных. Но это уже другая история, как делать серверные приложения. И тут информации для нескольких книг наберется, а не для коммента здесь.

                      Удачи!
                        0

                        Спасибо.
                        Ну вот сейчас меня в целом устраивает flask+SQLAlchemy. (вообще дома разрабатываю на SQLlite, но сейчас это дело сильно усложняется отсутствием возможности менять relations в готовой схеме)
                        Из задач: календарь, немножко CRM, статьи (в общем, контента таблиц на 30-40)
                        В целом, конечно, это все оч неплохо, и удобно, что все в одном месте. Но очень напрягает отсутствие поддержки IDE для шаблонов Jinja\плагинов flask. В общем, каждый чих приходится покрывать тестами, что несколько бесит.
                        Да и вообще, я уже отвык без MyPy работать. Ну а потом во flutter привлекает возможность легкой миграции из веба в native, и в принципе, как уже написал, dart очень понравился.


                        Вообще, конечно, веб для меня — новая и, прямо скажем, нежеланная область. Но в целом, логику построения структуры я понимаю. Мне просто дико некомфортно возвращаться в область тотального отсутствия контроля над ситуацией без обращения к рантайму...

                          +1
                          Думаю, что Flutter вам стоит рассматривать как браузер. Только вместо браузера у вас Flutter приложение. И вместо веб странички вы делаете приложение на Dart/Flutter. А вот остальные коммуникации — теже самые подходы. Регистрация, авторизация (JWT), проверка входящих данных, права доступа, формирование ответа итд итд итд — все это будет тоже самое, что и для веба, ну конечно в рамках вашего приложения.

                          Мне конечно сложно оценить ваше приложение и его возможности. Поэтому я написал выше изходя из своего опыта.
                      0
                      Вопрос немного не в тему, но возможно знающие люди подскажут.
                      Есть ли рускоязычные чаты по Flutter?
                      Telegram/Gitter/Discord/Slack

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое