Flutter EasyLoading — упростите глобальное всплывающее уведомление/загрузку

Flutter

flutter_easyloading: простой в использованииFlutterПлагин, включающий 23 вида анимационных эффектов загрузки, отображение индикатора выполнения, отображение тостов. Реализация Pure Flutter, поддержка iOS, Android.

адрес с открытым исходным кодом:GitHub.com/ Look Oh Look Yellow/ Волосы…

предисловие

FlutterдаGoogleНабор кроссплатформенных программ с открытым исходным кодом, запущенных в 2017 году.UIкаркас, который может быстроiOS,Androidа такжеWebСоздавайте высококачественные нативные пользовательские интерфейсы на платформе.FlutterС момента своего выпуска можно сказать, что он очень популярен и привлек большое количествоAppнативные разработчики,WebИменно потому, что разработчики вложили в свое вооружение одно за другимFlutterNova Field - это кроссплатформенная, в целом, его экология еще не идеальна, я считаю, что студенты, привыкли к родной разработке, колесо, безусловно, не нашел своего рода главы о чувстве на руке Левина. Например, эта статья о упоминании, какFlutterПростая и удобная презентация в приложенииToastилиLoadingУпаковать?

проводить исследования

pubЯ нашел еще несколько отличных плагинов:

  • FlutterToast: Этот плагин должен быть у многих новичковFlutterЭто зависит от натива, но проблемы на уровне пользовательского интерфейса лучше всего решать на стороне Flutter, что удобно для последующего обслуживания, а также может уменьшить проблемы с совместимостью;
  • flutter_oktoast: чистыйFlutterСквозная реализация, легко звонить. но отсутствуетloading, Дисплей прогресса, вы можете настроить вашу реализацию;

试用过后,发现这些插件都或多或少不能满足我们的产品需求,于是便结合自己产品的需求来造了这么个轮子,也希望可以帮到有需要的同学们。 Предварительный просмотр эффекта:

flutter_easyloading

выполнить

реализация showDialog

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

Future<T> showDialog<T>({
  @required BuildContext context,
  bool barrierDismissible = true,
  @Deprecated(
    'Instead of using the "child" argument, return the child from a closure '
    'provided to the "builder" argument. This will ensure that the BuildContext '
    'is appropriate for widgets built in the dialog. '
    'This feature was deprecated after v0.2.3.'
  )
  Widget child,
  WidgetBuilder builder,
  bool useRootNavigator = true,
})

Есть обязательный параметрcontext, должно быть, был в контакте сFlutterСтуденты, которые развивались в течение определенного периода времени, будут правы.BuildContextпонимать. Проще говоряBuildContextэто построитьWidgetКонтекст приложения в , этоFlutterважные части.BuildContextПоявляется только в двух местах:

  • StatelessWidget.buildВ методе: создатьStatelessWidgetизbuildметод
  • StateStatefulWidgetизStateобъектbuildStateПеременная-член

СвязанныйBuildContextshowDialogРеализовать всплывающую операцию окна, то вопрос, который мы считаем, так это то, как все удобно получить и быстроBuildContext, чтобы реализовать всплывающее окно. Если одноклассник использует егоshowDialogТаким образом, я полагаю, вы найдете, доступ в любое местоBuildContextЭто не так просто и создает много ненужного кода.

Итак, нам просто придется использовать этот крайне недружественный подход?

Конечно нет, продолжайте читать.

Введение в трепетание EasyLoading

Flutter EasyLoadingFlutter23ДобрыйloadingToastэкспонат. чистыйFlutteriOS,Android.先简单看下如何使用Flutter EasyLoading.

Установить

Добавьте следующий код в свой проектpubspec.yamlдокумент:

dependencies:
  flutter_easyloading: ^1.1.0 // 请使用最新版

импорт

import 'package:flutter_easyloading/flutter_easyloading.dart';

как использовать

Во-первых, используйтеFlutterEasyLoadingКомпонент обертывает ваш компонент приложения:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// 子组件通常为 [MaterialApp] 或者 [CupertinoApp].
    /// 这样做是为了确保 loading 组件能覆盖在其他组件之上.
    return FlutterEasyLoading(
      child: MaterialApp(
        title: 'Flutter EasyLoading',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Flutter EasyLoading'),
      ),
    );
  }
}

Тогда, пожалуйста, наслаждайтесь:

EasyLoading.show(status: 'loading...'); 

EasyLoading.showProgress(0.3, status: 'downloading...');

EasyLoading.showSuccess('Great Success!');

EasyLoading.showError('Failed with Error');

EasyLoading.showInfo('Useful Information.');

EasyLoading.dismiss();

Пользовательский стиль

Во-первых, давайте посмотрим наFlutter EasyLoadingВ настоящее время поддерживаются пользовательские свойства:

/// loading的样式, 默认[EasyLoadingStyle.dark].
EasyLoadingStyle loadingStyle;

/// loading的指示器类型, 默认[EasyLoadingIndicatorType.fadingCircle].
EasyLoadingIndicatorType indicatorType;

/// loading的遮罩类型, 默认[EasyLoadingMaskType.none].
EasyLoadingMaskType maskType;

/// 文本的对齐方式 , 默认[TextAlign.center].
TextAlign textAlign;

/// loading内容区域的内边距.
EdgeInsets contentPadding;

/// 文本的内边距.
EdgeInsets textPadding;

/// 指示器的大小, 默认40.0.
double indicatorSize;

/// loading的圆角大小, 默认5.0.
double radius;

/// 文本大小, 默认15.0.
double fontSize;

/// 进度条指示器的宽度, 默认2.0.
double progressWidth;

/// [showSuccess] [showError] [showInfo]的展示时间, 默认2000ms.
Duration displayDuration;

/// 文本的颜色, 仅对[EasyLoadingStyle.custom]有效.
Color textColor;

/// 指示器的颜色, 仅对[EasyLoadingStyle.custom]有效.
Color indicatorColor;

/// 进度条指示器的颜色, 仅对[EasyLoadingStyle.custom]有效.
Color progressColor;

/// loading的背景色, 仅对[EasyLoadingStyle.custom]有效.
Color backgroundColor;

/// 遮罩的背景色, 仅对[EasyLoadingMaskType.custom]有效.
Color maskColor;

/// 当loading展示的时候,是否允许用户操作.
bool userInteractions;

/// 展示成功状态的自定义组件
Widget successWidget;

/// 展示失败状态的自定义组件
Widget errorWidget;

/// 展示信息状态的自定义组件
Widget infoWidget;

потому чтоEasyLoadingявляется глобальным синглтоном, поэтому мы можем настроить его стиль в любом месте:

EasyLoading.instance
  ..displayDuration = const Duration(milliseconds: 2000)
  ..indicatorType = EasyLoadingIndicatorType.fadingCircle
  ..loadingStyle = EasyLoadingStyle.dark
  ..indicatorSize = 45.0
  ..radius = 10.0
  ..backgroundColor = Colors.green
  ..indicatorColor = Colors.yellow
  ..textColor = Colors.yellow
  ..maskColor = Colors.blue.withOpacity(0.5);

Дополнительные типы анимации индикатора для просмотраflutter_spinkit showcase

можно увидеть,Flutter EasyLoadingИнтеграция и довольно проста в использовании, и имеет множество пользовательских стилей, вы всегда будете довольны.

Flutter EasyLoadingКод.

Flutter EasyLoading

  • Overlay,OverlayEntry
  • CustomPaintа такжеCanvasРеализовать круговую зачистку прогресса

Overlay, OverlayEntry реализуют глобальное всплывающее окно

Первый взгляд на официальномOverlayописание:

/// A [Stack] of entries that can be managed independently.
///
/// Overlays let independent child widgets "float" visual elements on top of
/// other widgets by inserting them into the overlay's [Stack]. The overlay lets
/// each of these widgets manage their participation in the overlay using
/// [OverlayEntry] objects.
///
/// Although you can create an [Overlay] directly, it's most common to use the
/// overlay created by the [Navigator] in a [WidgetsApp] or a [MaterialApp]. The
/// navigator uses its overlay to manage the visual appearance of its routes.
///
/// See also:
///
///  * [OverlayEntry].
///  * [OverlayState].
///  * [WidgetsApp].
///  * [MaterialApp].
class Overlay extends StatefulWidget {}

То есть,OverlayЯвляетсяStackизWidget,могуOverlayEntryвставить вOverlayв, сделать независимымchildОкно нависает над другимWidgetНад. Используя эту функцию, мы можем использоватьOverlayБудуMaterialAppилиCupertinoApploadingFlutterТолько в присутствииMaterialAppилиCupertinoAppкомпонент корневого узла. (Примечание: практика здесь относится кflutter_oktoastплагин, спасибо)

Кроме того, цель этого может также решить другую основную проблему:contextКэшируется в памяти, все последующие вызовы предоставлять не нужноcontext. Реализация заключается в следующем:

@override
Widget build(BuildContext context) {
  return Directionality(
    child: Overlay(
      initialEntries: [
        OverlayEntry(
          builder: (BuildContext _context) {
            // 缓存 context
            EasyLoading.instance.context = _context;
            // 这里的child必须是MaterialApp或CupertinoApp
            return widget.child;
          },
        ),
      ],
    ),
    textDirection: widget.textDirection,
  );
}
// 创建OverlayEntry
OverlayEntry _overlayEntry = OverlayEntry(
  builder: (BuildContext context) => LoadingContainer(
    key: _key,
    status: status,
    indicator: w,
    animation: _animation,
  ),
);

// 将OverlayEntry插入到Overlay中
// 通过Overlay.of()我们可以获取到App根节点的Overlay
Overlay.of(_getInstance().context).insert(_overlayEntry);

// 调用OverlayEntry自身的remove()方法,从所在的Overlay中移除自己
_overlayEntry.remove();

Overlay,OverlayEntryИх очень просто использовать и понимать, и мы можем использовать их в других сценариях использования, например, в подобныхPopupWindowэффект всплывающего окна, глобальная настройкаDialogвсплывающие окна и т.д. Пока мы используем его гибко, мы можем достичь многих желаемых эффектов.

CustomPaintа такжеCanvasРеализовать круговой рисунок индикатора выполнения

почти всеUIСистема обеспечит самостоятельную покраскуUIинтерфейс, который обычно предоставляет часть2DхолстCanvas,CanvasВнутренне инкапсулирует некоторый базовый рисунокAPI, Мы можемCanvas绘制各种自定义图形。 существуетFlutterCustomPaintCustomPainter

Давайте сначала посмотримCustomPaintКонструктор:

const CustomPaint({
  Key key,
  this.painter,
  this.foregroundPainter,
  this.size = Size.zero,
  this.isComplex = false,
  this.willChange = false,
  Widget child,
})
  • painter: фоновая кисть, которая будет отображаться за дочерними узлами;
  • foregroundPainter: рисование переднего плана, которое будет отображаться перед дочерними узлами
  • размер: когдаchildдляnullКогда от имени размера по умолчанию область рисования, если естьchildзатем игнорируйте этот параметр, размер холстаchildразмер. Если естьchildНо если вы хотите указать холст определенного размера, вы можете использоватьSizeBoxпакетCustomPaintвыполнить.
  • isComplex: сложный ли рисунок, если да,FlutterНекоторые стратегии кэширования применяются для уменьшения накладных расходов на повторный рендеринг.
  • willChange: иisComplexПри совместном использовании, когда кэширование включено, это свойство указывает, изменится ли рисунок в следующем кадре.

Как видите, нам нужно предоставить кисти переднего плана или фона при рисовании, и обе они могут быть предоставлены одновременно. Наши кисти должны наследоватьCustomPainterмы реализуем реальную логику рисования в классе кисти.

Далее посмотрим как пройтиCustomPainterНарисуйте круговой индикатор выполнения:

class _CirclePainter extends CustomPainter {
  final Color color;
  final double value;
  final double width;

  _CirclePainter({
    @required this.color,
    @required this.value,
    @required this.width,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..strokeWidth = width
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;
    canvas.drawArc(
      Offset.zero & size,
      -math.pi / 2,
      math.pi * 2 * value,
      false,
      paint,
    );
  }

  @override
  bool shouldRepaint(_CirclePainter oldDelegate) => value != oldDelegate.value;
}

Сверху мы можем видеть это,CustomPainterВиртуальная функция определена вpaint:

void paint(Canvas canvas, Size size);

  • Холст: Холст, включая различные методы рендеринга, такие какdrawLine(画线),drawRect(画矩形),drawCircle(画圆)Ждать

Теперь, когда у нас есть холст, нам нужна кисть.Flutterпри условииPaintкласс для реализации кистей. И вы можете настроить различные свойства кисти, такие как толщина, цвет, стиль и т. д., например:

final paint = Paint()
  ..color = color // 颜色
  ..strokeWidth = width // 宽度
  ..style = PaintingStyle.stroke
  ..strokeCap = StrokeCap.round;

Наконец, нам просто нужно использоватьdrawArcМетод рисует дугу:

canvas.drawArc(
  Offset.zero & size,
  -math.pi / 2,
  math.pi * 2 * value,
  false,
  paint,
);

На этом мы закончили рисование индикатора выполнения. Кроме того, нам также необходимо обратить внимание на проблему производительности рисования. К счастью, класс предоставляет переопределениеshouldRepaintметод, этот метод определяет, когда холст будет перерисован, что весьма эффективно для повышения производительности рисования в сложном рисовании.

@override
bool shouldRepaint(_CirclePainter oldDelegate) => value != oldDelegate.value;

Эпилог

без сомнений,FlutterБудущее светлое, и может быть еще много проблем, но я верю, что больше людей захотят сопровождатьFlutter一起成长。 Ждать с нетерпениемFlutterFlutter EasyLoading

Flutter EasyLoadingДля вашей помощи.