Сегодня расскажу, как сделать кнопку загрузки во Flutter, которая умеет менять свое состояние: от обычной кнопки до загрузки с индикатором и кнопкой отмены. Такой подход пригодится, если вы хотите, чтобы пользователь видел прогресс, не нажимал на кнопку несколько раз или знал, когда загрузка завершилась.
Что мы хотим сделать?
Кнопка будет вести себя вот так:
Сначала — кнопка с текстом GET ➡️ нажимаем — она превращается в спиннер (идет подготовка загрузки) ➡️ потом появляется круговая загрузка с иконкой отмены ➡️ когда все скачалось — кнопка показывает OPEN
1. Создаем виджет DownloadButton
Это обычный StatelessWidget, который получает извне текущее состояние загрузки и отображает нужный UI.
enum DownloadStatus {
notDownloaded,
fetchingDownload,
downloading,
downloaded,
}2. Показываем форму кнопки
Когда ничего не загружается — кнопка с закругленными краями.
Когда начинается загрузка — кнопка превращается в прозрачный круг (чтобы потом анимировать индикатор поверх него). Пример:
AnimatedContainer(
duration: transitionDuration,
decoration: ShapeDecoration(
shape: isDownloading || isFetching
? CircleBorder()
: StadiumBorder(),
color: isDownloading || isFetching
? Colors.transparent
: CupertinoColors.lightBackgroundGray,
),
child: ...
);
3. Добавляем текст
GET → когда еще не загружено
OPEN → когда уже загружено
В промежуточных состояниях текст скрыт
AnimatedOpacity(
opacity: isDownloading || isFetching ? 0.0 : 1.0,
duration: transitionDuration,
child: Text(
isDownloaded ? 'OPEN' : 'GET',
style: TextStyle(
fontWeight: FontWeight.bold,
color: CupertinoColors.activeBlue,
),
),
);
4. Добавляем индикатор загрузки
Если статус fetchingDownload — отображаем крутящийся спиннер.
Если downloading — прогресс-бар и иконка «стоп» по центру, чтобы отменить загрузку.
Stack(
alignment: Alignment.center,
children: [
CircularProgressIndicator(value: progress),
if (isDownloading)
Icon(Icons.stop, size: 14, color: CupertinoColors.activeBlue),
],
);
5. Обработка нажатий
Когда пользователь нажимает кнопку — вызывается соответствующий колбэк:
void _onPressed() {
switch (status) {
case DownloadStatus.notDownloaded:
onDownload();
break;
case DownloadStatus.downloading:
onCancel();
break;
case DownloadStatus.downloaded:
onOpen();
break;
case DownloadStatus.fetchingDownload:
break;
}
}🟢В итоге — получаем кнопку с красивой анимацией и демонстрацией происходящего.
Подробнее можно прочитать в официальной документации.
