Flutter: использование пакетов

Не все йогурты одинаково полезны (с)

Иногда стандартных библиотек поставляемых с Fllutter не хватает, а самому что-то писать затруднительно — выходом может служить использование уже написанного и опакеченого кода. Все пакеты Flutter находятся на pub.dev, для добавления любого из пакетов с этого сайта в проект, достаточно добавить в pubspec.ymal проекта зависимость. Например:

dependencies:
  fluttertoast: ^8.0.9

После чего Android Studio предложит обновить зависимости. Далее добавим в main.dart импортируемую библиотеку:

import 'package:fluttertoast/fluttertoast.dart';

Далее непосредственное использование:

 ListTile(
                onTap: (){
                  Fluttertoast.showToast(
                      msg: "Здраствуйте я ваша дядя..",
                      toastLength: Toast.LENGTH_SHORT,
                      gravity: ToastGravity.CENTER,
                      timeInSecForIosWeb: 1,
                      backgroundColor: Colors.red,
                      textColor: Colors.white,
                      fontSize: 16.0
                  );
                },

Flutter: переход между экранами

Продолжаем работать с приложением из предыдущей статьи.

А что если логика работы приложения не ограничивается одним экраном? Создадим файл /lib/pages/about.dart

import 'package:flutter/material.dart';

class AboutMe extends StatefulWidget {
  _AboutMeState createState() => _AboutMeState(); // сюда передаем текущее состояние страницы
}
class _AboutMeState extends State<AboutMe> {// _ впереди класса, означает чтоб скрыть доступ из другх файлов
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('О нас'))
    );
  }
}

А в файл page1.dart добавим связку со страницей:

import 'package:invent/pages/about.dart';

И в меню строчку вызова новой страницы:

ListTile(
                onTap: (){
                  Navigator.push(context, MaterialPageRoute(builder: (context) => AboutMe()));
                },
                leading: Icon(Icons.account_balance_outlined,), title: Text('About'),
                tileColor: Color(0xFFF5F5F5),
                dense: false,
              ),

В результате получим переход на другую страницу:

Можно заметить, что срелка «назад» добавилась автоматичеки. Программно это вызов:

Navigator.pop(context);

Navigator – виджет-класс, позволяющий управлять стеком дочерних виджетов, т.е. открывать, закрывать и переключать окна или страницы. Когда мы используем MaterialApp, то экземпляр класса Navigator уже создан

Второй способ переключения между экранами

Существует второй штатный способ переключения между экранами. Особой разницы между ними нет, каждый использует по своему усмотрению. Flutter позволяет переключаться между экранами при помощи «маршрутов». Для этого в главном файле вместо вызова home: Page1() добавим маршруты:

import 'package:invent/pages/about.dart';
import 'pages/page1.dart';
...
 Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Инвентаризация ССК',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
        initialRoute: '/',
        routes: {
          '/':(BuildContext context) => Page1(),
          '/AboutMe':(BuildContext context) => AboutMe()
        }
    );
  }

И соответственно тогда вызов перехода будет теперь осуществлять вот так:

 ListTile(
                onTap: (){
                  Navigator.pushNamed(context, "/AboutMe");
                },
                leading: Icon(Icons.account_balance_outlined,), title: Text('About'),
                tileColor: Color(0xFFF5F5F5),
                dense: false,
              ),

Flutter: диалоговое окно

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

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

AlertDialog — подготовка данных для отображения

showDialog — непосредственные вывод диалога пользователю

Оформим диалог в виде отдельно функции:

SureExitDialog(BuildContext context) {
    Widget cancelButton = TextButton(
      child: Text("Остаться"),
      onPressed:  () {Navigator.pop(context);},
    );
    Widget yesButton = TextButton(
      child: Text("Да"),
      onPressed:  () {
                if (Platform.isAndroid) {
                  SystemChannels.platform.invokeMethod(
                      'SystemNavigator.pop');
                } else {
                  exit(0);
                };
},
    );
    AlertDialog alert = AlertDialog(
      title: Text("Подтверждение"),
      content: Text("Вы действительно хотите выйти из приложения?"),
      actions: [
        cancelButton,
        yesButton,
      ],
    );
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }

Добавим вызов диалога из нажатия кнопки выхода:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      appBar: AppBar(
        backgroundColor: Colors.green,
        automaticallyImplyLeading: true,
        title: Text(
          'Инвентаризация'
        ),
        actions: [
          new IconButton(
              onPressed: () {
                SureExitDialog(context);
              },
              icon: new Icon(Icons.exit_to_app)
          ),
        ],
        centerTitle: true,
        elevation: 4,
      ),
...

Результат:

Для любителей диалоговых окон во весь экран (что актуально для мобильных, вот еще вариант:

showDialog(
      context: context,
      builder: (BuildContext context) {
        return Align (
          alignment: Alignment.bottomCenter,
            child:
            Container(
              width: double.infinity,
                decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(32.0),
                        topRight: Radius.circular(32.0))),
              child:Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Material(
                          child: Text("Подтверждение",
                              style: TextStyle(
                                  fontSize: 14.0, color: Colors.black))),
                    ),
                    Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Material(
                          child: Text("Вы действительно хотите выйти из приложения?",
                              style: TextStyle(
                                  fontSize: 14.0, color: Colors.black))),
                    ),
                    cancelButton,
                    yesButton
                  ]
              )
            )
        );
      },
    );
  }

Результат:

Flutter: реализуем выплывающее меню слева

Меню слева в Flutter реализуется при помощи виджета drawer. Заголовок меню отображается при помощи виджета DrawerHeader, а пункты меню при помощи ListTiles.

В результате добавления к предыдущему примеру (удалите leading: new Icon(Icons.menu), ) кода:

 drawer: new Drawer(
          child: new ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              new DrawerHeader(
                  child: new Text("Инвентаризация ТМЦ",textAlign: TextAlign.center,style: Theme.of(context).textTheme.headline4),
                  decoration: new BoxDecoration(color: Colors.blue),
              ),
              ListTile(
                title: const Text('Загрузить список',style: TextStyle(color: Colors.green,fontSize: 26, backgroundColor: Colors.amberAccent),),
                onTap: () {},
              ),
              ListTile(title: const Text('Выгрузить результаты',style: TextStyle(fontSize: 26),),onTap: () {}),
              ListTile(title: const Text('Сканировать',style: TextStyle(fontSize: 26),),onTap: () {}),
            ],
          ),

Получим нечто вроде:

Обработка выбора пункта меню происходит в onTap(){} Например закрыть список можно:

 Navigator.pop(context);

Пример как сделать в шапке меню две и более мтрочки:

              new DrawerHeader(
                  child: Column(
                    children: <Widget>[
                        new Text("Инвентаризация ТМЦ",textAlign: TextAlign.center,style: Theme.of(context).textTheme.headline4),
                        new Text("Меня зовут Вася",textAlign: TextAlign.center,style: Theme.of(context).textTheme.headline5),
                      ],
                  ),
              ),

Разделение пунктов меню:

              ListTile(title: const Text('Выгрузить результаты',style: TextStyle(fontSize: 26),),onTap: () {}),
              Divider(color: Colors.black87),
              ListTile(title: const Text('Сканировать',style: TextStyle(fontSize: 26),),onTap: () {}),

Добавить фото в заголовок меню:

 new DrawerHeader(
                decoration: BoxDecoration(
                  image: DecorationImage(
                    fit: BoxFit.scaleDown,
                    image: AssetImage("./lib/images/lenin.jpg"),
                  ),
                ),
                  child: Column(
                    children: <Widget>[
                        new Text("Инвентаризация ТМЦ",textAlign: TextAlign.center,style: Theme.of(context).textTheme.headline4),
                        new Text("Меня зовут Вася",textAlign: TextAlign.center,style: Theme.of(context).textTheme.headline5),
                      ],
                  ),
              ),

Может выйти ошибка:

The following assertion was thrown resolving an image codec:
Unable to load asset: ./lib/resources/logo_1200_630.jpg

Для того чтобы исправить, нужно в pubspec.yaml добавить:

В результате получится что-то вроде:

P.S. Открыл для себя https://app.flutterflow.io где UI можно рисовать «визульно», и на выходе получать код.Это таки несколько удобнее и быстрее. Далее буду пытаться использовать этот сервис

Flutter: учимся создавать AppBar

Любое приложение чаще всего запускается с главного экрана, на котором расположено некое меню. С него и начнем. Возьмём приложение из предыдущей статьи, и продолжим «стругать»:

import 'package:flutter/material.dart';
class Page1 extends StatefulWidget {
  _Page1State createState() => _Page1State(); // сюда передаем текущее состояние страницы
}
class _Page1State extends State<Page1> { // _ впереди класса, означает чтоб скрыть доступ из другх файлов
  @override
  Widget build(BuildContext context) {
    return Scaffold( // чаще всего используемый "корневой" виджет, который позволяет добавлять в себя другие: AppBar, BottomNavigationBar,Drawer, FloatingActionButton и т.п.
        appBar: AppBar(
            title: Text("Инвентаризация"),
            leading: new Icon(Icons.menu),
            actions: <Widget>[
              new IconButton(
                  onPressed: (){},
                  icon: new Icon(Icons.exit_to_app)
              )
            ]
        ),
        body: Center(
            child: Text(
              "Ууу как всё запущено пациент..",
              textAlign: TextAlign.center,
              style: Theme.of(context).textTheme.headline3,
            )
        )
    );
  }

}

Здесь мы добавили иконку развертываемого меню в левом углу и виджет-кнопку «Выхода» из приложения.

Чтобы реализовать выход из приложения, нужно добавить импорт библиотеки и в OnPressed собственно команду выхода:

...
import 'package:flutter/services.dart';
...
                  onPressed: () {
                                        if (Platform.isAndroid) {
                      SystemChannels.platform.invokeMethod(
                          'SystemNavigator.pop');
                    } else {
                      exit(0);
                    };
                  },

Как видите, тут мы уже подобрались к толике кросплатформенности. Что работает на одной платформе, может не работать на другой. И функционал «выхода» в одной из этих специфик.

1 6 7 8 9