Так что возможность написать одно приложение для iOS и Android - это глупо, но, как вещь, способная на большее, Flutter, эээ, также способен на большее. Что, если вместо того, чтобы просто пытаться максимально точно имитировать две стандартные платформы, мы вложим больше энергии в создание вещей, которые легко достижимы с помощью Skia, чего вы не смогли бы сделать без серьезных усилий в нативной версии?

Пользователь загружает ваше приложение, открывает его и видит, как обычный макет повторяется примерно в 207% всех мобильных устройств. Она опытный пользователь; у нее было приложение или два в день. Она небрежно замечает: «О, панель приложений с навигационной панелью, я знаю, как вы работаете. И это нормально, я говорю это ». А потом БАМ:

Она опускает кронут. Ее мир перевернут. «Мы в Нарнии?!?» Она увидела будущее, и оно покоится на вашей эшафоте:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: ProgressAppBar(
        scaffoldKey: _scaffoldKey,
        title: 'My Map',
        progress: _taskProgress,
        onActionTapped: () {
          _openBottomSheet();
        },
      ),
      drawer: NavigationDrawer(
        currentRoute: Home.route,
      ),
      body: Container(
        ...
      ),
    );
  }

И там, где раньше правил наш верный виджет AppBar, теперь у нас есть:

Небольшое примечание о приведенной выше реализации ProgressAppBar: это была специальная вещь, которую я создал для работы с моим конкретным заголовком и действием панели приложения (со значком photo_album). Полученный код выглядит нативно с моими параметрами как в iOS, так и в Android, но если вы подключаете и запускаете свои вещи, вам следует дважды проверить, чтобы убедиться, что все по-прежнему размещено должным образом (вы можете, например, сделать снимки экрана своего приложения, используя обычный AppBar и сравните расположение элементов с настраиваемым). Если повезет, надеюсь, ваши вещи выстроятся в линию с минимальными усилиями или без них, и вы можете начать отображать индикатор прогресса с жирным стилем, который не блокирует взаимодействие пользователя с вашим экраном.

Давай пробежимся по нему. Scaffold appBar может принимать все, что реализует PreferredSizeWidget. Для удобства мы можем получить нужный размер виджета с помощью константы Flutter, kToolbarHeight. Теперь нам просто нужно создать что-то, что выглядит как нативный AppBar.

Как?

Со стопкой из трех контейнеров. Первый заполняет начальное состояние панели цветом акцента вашей темы. Вдобавок к этому есть поле с FractionallySizedBox, ширина которого определяется входным двойным значением. Таким образом, если отслеживаемый объект имеет прогресс 25% (или 0,25), мы увидим, что основной цвет темы занимает 25% ширины панели приложения. Когда он достигает 100% (или 1,0), мы визуально уведомляем пользователя о завершении фоновой задачи, а панель приложения заполняется основным цветом. Все это время третий контейнер наверху стека содержал обычные элементы: гамбургер навигационного ящика, заголовок, который расширяется, чтобы занять доступное место, и значок действия (с функцией обратного вызова, переданной в конструктор ProgressAppBar).

Говоря о NavigationDrawer, мы можем получить к нему доступ через Scaffold, передав GlobalKey ‹ScaffoldState›. Если вы посмотрите на пример кода экрана, вы увидите, что мы передаем экземпляр _scaffoldKey как Scaffold, так и ProgressAppBar. Этот экземпляр может быть просто глобальной переменной в состоянии вашего экрана:

class _HomeState extends State<Home> {
  // Access Scaffold from ProgressAppBar.
  final GlobalKey<ScaffoldState> _scaffoldKey =
    GlobalKey<ScaffoldState>();
  ...
}

Что касается переменной ValueNotifier ‹double› progress, которую вам нужно передать, вам нужно будет установить ее значение в соответствии с любой задачей известной степени или продолжительности, которую вы отслеживаете. Скорее всего, вы захотите инициализировать его значением 0%, например:

// Task progress.
ValueNotifier<double> _taskProgress =
  ValueNotifier<double>(0.0);

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

_taskProgress.value = 0.66;

при каждом приращении, пока вы не дойдете до 1.0, где вам следует позаботиться о том, чтобы ограничить значение, чтобы оно не поднималось выше (если, конечно, вы не хотите указать прогресс более 100% с помощью каких-либо других аккуратных UI штука, но настраиваемая панель приложений, как она, была разработана только для работы с максимальным значением 1.0).

Вот и все! А теперь выходи и измени мир.