Точки обмена скриншотами Flutter

Flutter

введение

Функция обмена приложением обычно включает обмен снимками экрана. Как правило, функция скриншота Flutter выполняется черезRepaintBoundaryКонкретная реализация очень проста и не будет здесь подробно останавливаться. В этой статье в основном речь идет о двух моментах: длинных скриншотах и ​​сшивке изображений.

1. Длинный скриншот

В реальных потребностях область, которая должна быть скриншон, может превышать один экран, то есть длинный скриншот требуется. Эта область обычно вложена в прокручиваемому контейнере, напримерSingleChildScroolViewЖдать. Если мы обернем контейнер прокрутки напрямуюRepaintBoundary,Например:

RepaintBoundary(
  key: key ,
  child: SingleChildScrollView(
    child: Column(
      children:[
            widget1,
            widget2,
            widget3,
            ...
            ]
            ),
          ),
        );

Когда вы получите снимок экрана, вы обнаружите, что на снимке экрана отображается только та область, которая в данный момент отображается на экране! Причина на самом деле довольно проста:RepaintBoundaryБудет измерять ширину и высоту прямого дочернего виджета, а в это время его прямого дочернего виджета (в примереSingleChildScrollView) — максимальная ширина и высота экрана. Решение тоже очень простое: поставитьRepaintBoundaryУстановите на внешний слой, который действительно нужно разрезать, как правилоColumn(Ширина и высота этого виджета — это ширина и высота, которые мы на самом деле хотим вырезать). Приведенный выше пример будет изменен на:

SingleChildScrollView(
  child: RepaintBoundary(
    key: key ,
    child: Column(
      children:[
            widget1,
            widget2,
            widget3,
            ...
            ]
            ),
          ),
        );

Еще одна вещь, которую следует отметить, это то, что если цвет фона страницы установлен наRepaintBoundaryВнешний слой, то снимок экрана имеет прозрачный фон, затем вам нужно установить цвет фона во внутреннем слое.

2. Сшивка картинок

Идеальная ситуация для длинного снимка экрана выше была бы такой:SingleChildScrollViewЭто позволяет нам установить слой в дочернемRepaintBoundary, но на практике может быть и такCustomScrollViewЭтот тип строгих ограничений на детей, в это время нам может потребоваться использовать аналогичныйSliverToBoxAdapterТакой контейнер, и каждый набор на ребенкаRepaintBoundary,Например:

CustomScrollView(
          slivers: <Widget>[
            ///appbar
            SliverAppBar(
              flexibleSpace: RepaintBoundary(
                key: key,
                child: FlexibleSpaceBar(... ),
              ),
            ),
            ///内容
            SliverToBoxAdapter(
              child: RepaintBoundary(
                key: key2,
                child:Column(...)
                )
            ),
          ],
        )

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

Для сшивания изображений моя идея состоит в том, чтобы: использоватьpaintcanvas

  1. Рассчитайте максимальную ширину / высоту в зависимости от ширины и высоты каждого изображения для разделения
  2. Если вы хотите поддерживать альбомную и портретную ориентацию, вам также необходимо определить ориентацию
  3. Ширина и высота изображений могут быть разными, и их необходимо масштабировать, чтобы они были согласованными (ширина вертикального расположения должна быть одинаковой, а высота горизонтального расположения должна быть одинаковой).

Конкретная реализация выглядит следующим образом:

(1)Определить параметры, открытые для внешнего мира.imageList список изображений (обязательно), направление направления, масштабируется ли подгонка, чтобы быть последовательным.

(2)

 ///计算最大图片宽/高
 int maxWidth = 0;
 int maxHeight = 0;
 imageList.forEach((image) {
      if (direction == Axis.vertical) {
        if (maxWidth < image.width) maxWidth = image.width;
      } else {
        if (maxHeight < image.height) maxHeight = image.height;
      }
    });
///建立变量记录总高及总宽    
int totalHeight = maxHeight;
int totalWidth = maxWidth;

(3)Инициализируйте управление краской.

    ui.PictureRecorder recorder = ui.PictureRecorder();
    final paint = Paint();
    Canvas canvas = Canvas(recorder);

(4)Нарисуйте в зависимости от того, подходит он или нет.Если подойдет, он должен быть масштабированcanvasДля соответствия ширине/высоте и записи точки координат

  double dx = 0;
  double dy = 0;
    //draw images into canvas
    imageList.forEach((image) {
      double scaleDx = dx;
      double scaleDy = dy;
      double imageHeight = image.height.toDouble();
      double imageWidth = image.width.toDouble();
      if (fit) {
        //scale the image to same width/height
        canvas.save();
        if (direction == Axis.vertical && image.width != maxWidth) {
          canvas.scale(maxWidth / image.width);
          scaleDy *= imageWidth/maxWidth;
          imageHeight *= maxWidth/imageWidth;
        } else if (direction == Axis.horizontal && image.height != maxHeight) {
          canvas.scale(maxHeight / image.height);
          scaleDx *= imageHeight/maxHeight;
          imageWidth *= maxHeight/imageHeight;
        }
        canvas.drawImage(image, Offset(scaleDx, scaleDy), paint);
        canvas.restore();
      } else {
        //draw directly
        canvas.drawImage(image, Offset(dx, dy), paint);
      }
      //accumulate dx/dy
      if (direction == Axis.vertical) {
        dy += imageHeight;
        totalHeight += imageHeight.floor();
      } else {
        dx += imageWidth;
        totalWidth += imageWidth.floor();
      }
    });

(5)выходное изображение.Формат по умолчаниюui.ImageЕсли нужноUint8ListилиFileПодождите, вам нужно преобразовать это самостоятельно.

return recorder.endRecording().toImage(totalWidth, totalHeight);

Предварительный просмотр эффекта:

Элементы управления сшиванием изображений были доставлены на рынок пабов:merge_images, который поставляется с некоторым преобразованием формата изображения и функцией прямого использования отображения виджета, вы можете использовать его, если вам это нужно.