extended_image 0.6.4

  • Readme
  • Changelog
  • Example
  • Installing
  • 99

extended_image #

pub package GitHub stars GitHub forks GitHub license GitHub issues flutter-candies

Language: English | 中文简体

A powerful official extension library of image, which support placeholder(loading)/ failed state, cache network, zoom pan image, photo view, slide out page, editor(crop,rotate,flip), paint custom etc.

Table of contents #

Cache Network #

Simple use #

You can use ExtendedImage.network as Image Widget

ExtendedImage.network(
  url,
  width: ScreenUtil.instance.setWidth(400),
  height: ScreenUtil.instance.setWidth(400),
  fit: BoxFit.fill,
  cache: true,
  border: Border.all(color: Colors.red, width: 1.0),
  shape: boxShape,
  borderRadius: BorderRadius.all(Radius.circular(30.0)),
  //cancelToken: cancellationToken,
)

Use Extendednetworkimageprovider #

ExtendedNetworkImageProvider

   ExtendedNetworkImageProvider(
      this.url, {
      this.scale = 1.0,
      this.headers,
      this.cache: false,
      this.retries = 3,
      this.timeLimit,
      this.timeRetry = const Duration(milliseconds: 100),
      CancellationToken cancelToken,
    })  : assert(url != null),
          assert(scale != null),
          cancelToken = cancelToken ?? CancellationToken();
parameterdescriptiondefault
urlThe URL from which the image will be fetched.required
scaleThe scale to place in the [ImageInfo] object of the image.1.0
headersThe HTTP headers that will be used with [HttpClient.get] to fetch image from network.-
cachewhether cache image to localfalse
retriesthe time to retry to request3
timeLimittime limit to request image-
timeRetrythe time duration to retry to requestmilliseconds: 100
cancelTokentoken to cancel network requestCancellationToken()

Load State #

Extended Image provide 3 states(loading,completed,failed), you can define your state widget with loadStateChanged call back.

loadStateChanged is not only for network, if your image need long time to load, you can set enableLoadState(default value is ture for network and others are false) to ture

img

/// custom load state widget if you want
    final LoadStateChanged loadStateChanged;

enum LoadState {
  //loading
  loading,
  //completed
  completed,
  //failed
  failed
}

  ///whether has loading or failed state
  ///default is false
  ///but network image is true
  ///better to set it's true when your image is big and take some time to ready
  final bool enableLoadState;

ExtendedImageState(LoadStateChanged call back)

parameter/methoddescriptiondefault
extendedImageInfoimage info-
extendedImageLoadStateLoadState(loading,completed,failed)-
returnLoadStateChangedWidgetif this is ture, return widget which from LoadStateChanged fucntion immediately(width/height/gesture/border/shape etc, will not effect on it)-
imageProviderImageProvider-
invertColorsinvertColors-
imageStreamKeykey of image-
reLoadImage()if image load failed,you can reload image by call it-
abstract class ExtendedImageState {
  void reLoadImage();
  ImageInfo get extendedImageInfo;
  LoadState get extendedImageLoadState;

  ///return widget which from LoadStateChanged fucntion  immediately
  bool returnLoadStateChangedWidget;

  ImageProvider get imageProvider;

  bool get invertColors;

  Object get imageStreamKey;
}

demo code #

ExtendedImage.network(
  url,
  width: ScreenUtil.instance.setWidth(600),
  height: ScreenUtil.instance.setWidth(400),
  fit: BoxFit.fill,
  cache: true,
  loadStateChanged: (ExtendedImageState state) {
    switch (state.extendedImageLoadState) {
      case LoadState.loading:
        _controller.reset();
        return Image.asset(
          "assets/loading.gif",
          fit: BoxFit.fill,
        );
        break;
      case LoadState.completed:
        _controller.forward();
        return FadeTransition(
          opacity: _controller,
          child: ExtendedRawImage(
            image: state.extendedImageInfo?.image,
            width: ScreenUtil.instance.setWidth(600),
            height: ScreenUtil.instance.setWidth(400),
          ),
        );
        break;
      case LoadState.failed:
        _controller.reset();
        return GestureDetector(
          child: Stack(
            fit: StackFit.expand,
            children: <Widget>[
              Image.asset(
                "assets/failed.jpg",
                fit: BoxFit.fill,
              ),
              Positioned(
                bottom: 0.0,
                left: 0.0,
                right: 0.0,
                child: Text(
                  "load image failed, click to reload",
                  textAlign: TextAlign.center,
                ),
              )
            ],
          ),
          onTap: () {
            state.reLoadImage();
          },
        );
        break;
    }
  },
)

Zoom Pan #

img

ExtendedImage

parameterdescriptiondefault
modeimage mode (none,gestrue,editor)none
initGestureConfigHandlerinit GestureConfig when image is ready,for example, base on image width/height-
onDoubleTapcall back of double tap under ExtendedImageMode.Gesture-

GestureConfig

parameterdescriptiondefault
minScalemin scale0.8
animationMinScalethe min scale for zooming then animation back to minScale when scale endminScale _ 0.8
maxScalemax scale5.0
animationMaxScalethe max scale for zooming then animation back to maxScale when scale endmaxScale _ 1.2
speedspeed for zoom/pan1.0
inertialSpeedinertial speed for zoom/pan100
cacheGesturesave Gesture state (for example in ExtendedImageGesturePageView, gesture state will not change when scroll back),remember clearGestureDetailsCache at right timefalse
inPageViewwhether in ExtendedImageGesturePageViewfalse
ExtendedImage.network(
  imageTestUrl,
  fit: BoxFit.contain,
  //enableLoadState: false,
  mode: ExtendedImageMode.Gesture,
  initGestureConfigHandler: (state) {
    return GestureConfig(
        minScale: 0.9,
        animationMinScale: 0.7,
        maxScale: 3.0,
        animationMaxScale: 3.5,
        speed: 1.0,
        inertialSpeed: 100.0,
        initialScale: 1.0,
        inPageView: false);
  },
)

double tap animation #

onDoubleTap: (ExtendedImageGestureState state) {
  ///you can use define pointerDownPosition as you can,
  ///default value is double tap pointer down postion.
  var pointerDownPosition = state.pointerDownPosition;
  double begin = state.gestureDetails.totalScale;
  double end;

  //remove old
  _animation?.removeListener(animationListener);

  //stop pre
  _animationController.stop();

  //reset to use
  _animationController.reset();

  if (begin == doubleTapScales[0]) {
    end = doubleTapScales[1];
  } else {
    end = doubleTapScales[0];
  }

  animationListener = () {
    //print(_animation.value);
    state.handleDoubleTap(
        scale: _animation.value,
        doubleTapPosition: pointerDownPosition);
  };
  _animation = _animationController
      .drive(Tween<double>(begin: begin, end: end));

  _animation.addListener(animationListener);

  _animationController.forward();
},

Editor #

img

    ExtendedImage.network(
      imageTestUrl,
      fit: BoxFit.contain,
      mode: ExtendedImageMode.editor,
      extendedImageEditorKey: editorKey,
      initEditorConfigHandler: (state) {
        return EditorConfig(
            maxScale: 8.0,
            cropRectPadding: EdgeInsets.all(20.0),
            hitTestSize: 20.0,
            cropAspectRatio: _aspectRatio.aspectRatio);
      },
    );

ExtendedImage

parameterdescriptiondefault
modeimage mode (none,gestrue,editor)none
initEditorConfigHandlerinit EditorConfig when image is ready.-
extendedImageEditorKeykey of ExtendedImageEditorState to flip/rotate/get crop rect-

EditorConfig

parameterdescriptiondefault
maxScalemax scale of zoom5.0
cropRectPaddingthe padding between crop rect and image layout rect.EdgeInsets.all(20.0)
cornerSizesize of corner shapeSize(30.0, 5.0)
cornerColorcolor of corner shapeprimaryColor
lineColorcolor of crop linescaffoldBackgroundColor.withOpacity(0.7)
lineHeightheight of crop line0.6
eidtorMaskColorHandlercall back of eidtor mask color base on pointerDownscaffoldBackgroundColor.withOpacity(pointerdown ? 0.4 : 0.8)
hitTestSizehit test region of corner and line20.0
animationDurationauto center animation durationDuration(milliseconds: 200)
tickerDurationduration to begin auto center animation after crop rect is changedDuration(milliseconds: 400)
cropAspectRatioaspect ratio of crop rectnull(custom)
initCropRectTypeinit crop rect base on initial image rect or image layout rectimageRect

crop aspect ratio #

it's a double value, so it's esay for you to define by yourself. following are official values

class CropAspectRatios {
  /// no aspect ratio for crop
  static const double custom = null;

  /// the same as aspect ratio of image
  /// [cropAspectRatio] is not more than 0.0, it's original
  static const double original = 0.0;

  /// ratio of width and height is 1 : 1
  static const double ratio1_1 = 1.0;

  /// ratio of width and height is 3 : 4
  static const double ratio3_4 = 3.0 / 4.0;

  /// ratio of width and height is 4 : 3
  static const double ratio4_3 = 4.0 / 3.0;

  /// ratio of width and height is 9 : 16
  static const double ratio9_16 = 9.0 / 16.0;

  /// ratio of width and height is 16 : 9
  static const double ratio16_9 = 16.0 / 9.0;
}

crop,flip,reset #

  • add key for ExtendedImageEditorState

    final GlobalKey<ExtendedImageEditorState> editorKey =GlobalKey<ExtendedImageEditorState>();

  • rotate right

    editorKey.currentState.rotate(right: true);

  • rotate left

    editorKey.currentState.rotate(right: false);

  • flip

    editorKey.currentState.flip();

  • reset

    editorKey.currentState.reset();

crop data #

dart library(stable) #

  • add Image library into your pubspec.yaml, it's used to crop/rotate/flip image data
dependencies:
  image: any
  • get crop rect and raw image data from ExtendedImageEditorState
  ///crop rect base on raw image
  final Rect cropRect = state.getCropRect();

  var data = state.rawImageData;
  • convert raw image data to image libray data.
  /// it costs much time and blocks ui.
  //Image src = decodeImage(data);

  /// it will not block ui with using isolate.
  //Image src = await compute(decodeImage, data);
  //Image src = await isolateDecodeImage(data);
  final lb = await loadBalancer;
  Image src = await lb.run<Image, List<int>>(decodeImage, data);
  • crop,flip,rotate data
  //clear orientation
  src = bakeOrientation(src);

  if (editAction.needCrop)
    src = copyCrop(src, cropRect.left.toInt(), cropRect.top.toInt(),
        cropRect.width.toInt(), cropRect.height.toInt());

  if (editAction.needFlip) {
    Flip mode;
    if (editAction.flipY && editAction.flipX) {
      mode = Flip.both;
    } else if (editAction.flipY) {
      mode = Flip.horizontal;
    } else if (editAction.flipX) {
      mode = Flip.vertical;
    }
    src = flip(src, mode);
  }

  if (editAction.hasRotateAngle) src = copyRotate(src, editAction.rotateAngle);
  • convert to original image data

output is raw image data, you can use it to save or any other thing.

  /// you can encode your image
  ///
  /// it costs much time and blocks ui.
  //var fileData = encodeJpg(src);

  /// it will not block ui with using isolate.
  //var fileData = await compute(encodeJpg, src);
  //var fileData = await isolateEncodeImage(src);
  var fileData = await lb.run<List<int>, Image>(encodeJpg, src);

native library(faster) #

  • add ImageEditor library into your pubspec.yaml, it's used to crop/rotate/flip image data
dependencies:
  image_editor: any
  • get crop rect and raw image data from ExtendedImageEditorState
  ///crop rect base on raw image
  final Rect cropRect = state.getCropRect();

  var data = state.rawImageData;
  • prepare crop option
  final rotateAngle = action.rotateAngle.toInt();
  final flipHorizontal = action.flipY;
  final flipVertical = action.flipX;
  final img = state.rawImageData;

  ImageEditorOption option = ImageEditorOption();

  if (action.needCrop) option.addOption(ClipOption.fromRect(rect));

  if (action.needFlip)
    option.addOption(
        FlipOption(horizontal: flipHorizontal, vertical: flipVertical));

  if (action.hasRotateAngle) option.addOption(RotateOption(rotateAngle));
  • crop with editImage

output is raw image data, you can use it to save or any other thing.

  final result = await ImageEditor.editImage(
    image: img,
    imageEditorOption: option,
  );

more detail

Photo View #

ExtendedImageGesturePageView is the same as PageView and it's made for show zoom/pan image.

if you have cache the gesture, remember call clearGestureDetailsCache() method at the right time.(for example,page view page is disposed)

img

ExtendedImageGesturePageView

parameterdescriptiondefault
cacheGesturewhether should move pagetrue

GestureConfig

parameterdescriptiondefault
cacheGesturesave Gesture state (for example in ExtendedImageGesturePageView, gesture state will not change when scroll back),remember clearGestureDetailsCache at right timefalse
inPageViewwhether in ExtendedImageGesturePageViewfalse
ExtendedImageGesturePageView.builder(
  itemBuilder: (BuildContext context, int index) {
    var item = widget.pics[index].picUrl;
    Widget image = ExtendedImage.network(
      item,
      fit: BoxFit.contain,
      mode: ExtendedImageMode.Gesture,
      gestureConfig: GestureConfig(
        inPageView: true, initialScale: 1.0,
        //you can cache gesture state even though page view page change.
        //remember call clearGestureDetailsCache() method at the right time.(for example,this page dispose)
        cacheGesture: false
      ),
    );
    image = Container(
      child: image,
      padding: EdgeInsets.all(5.0),
    );
    if (index == currentIndex) {
      return Hero(
        tag: item + index.toString(),
        child: image,
      );
    } else {
      return image;
    }
  },
  itemCount: widget.pics.length,
  onPageChanged: (int index) {
    currentIndex = index;
    rebuild.add(index);
  },
  controller: PageController(
    initialPage: currentIndex,
  ),
  scrollDirection: Axis.horizontal,
),

Slide Out Page #

Extended Image support to slide out page as WeChat.

img

enable slide out page #

ExtendedImage

parameterdescriptiondefault
enableSlideOutPagewhether enable slide out pagefalse
heroBuilderForSlidingPagebuild Hero only for sliding page, the transfrom of sliding page must be working on Hero,so that Hero animation wouldn't be strange when pop pagenull

include your page in ExtendedImageSlidePage #

take care of onSlidingPage call back, you can update other widgets' state as you want. but, do not setState directly here, image state will changed, you should only notify the widgets which are needed to change

    return ExtendedImageSlidePage(
      child: result,
      slideAxis: SlideAxis.both,
      slideType: SlideType.onlyImage,
      onSlidingPage: (state) {
        ///you can change other widgets' state on page as you want
        ///base on offset/isSliding etc
        //var offset= state.offset;
        var showSwiper = !state.isSliding;
        if (showSwiper != _showSwiper) {
          // do not setState directly here, the image state will change,
          // you should only notify the widgets which are needed to change
          // setState(() {
          // _showSwiper = showSwiper;
          // });

          _showSwiper = showSwiper;
          rebuildSwiper.add(_showSwiper);
        }
      },
    );

ExtendedImageGesturePage

parameterdescriptiondefault
childThe [child] contained by the ExtendedImageGesturePage.-
slidePageBackgroundHandlerbuild background when slide pagedefaultSlidePageBackgroundHandler
slideScaleHandlercustom scale of page when slide pagedefaultSlideScaleHandler
slideEndHandlercall back of slide end,decide whether pop pagedefaultSlideEndHandler
slideAxisaxis of slide(both,horizontal,vertical)SlideAxis.both
resetPageDurationreset page position when slide end(not pop page)milliseconds: 500
slideTypeslide whole page or only imageSlideType.onlyImage
onSlidingPagecall back when it's sliding page, change other widgets state on page as you want-
Color defaultSlidePageBackgroundHandler(
    {Offset offset, Size pageSize, Color color, SlideAxis pageGestureAxis}) {
  double opacity = 0.0;
  if (pageGestureAxis == SlideAxis.both) {
    opacity = offset.distance /
        (Offset(pageSize.width, pageSize.height).distance / 2.0);
  } else if (pageGestureAxis == SlideAxis.horizontal) {
    opacity = offset.dx.abs() / (pageSize.width / 2.0);
  } else if (pageGestureAxis == SlideAxis.vertical) {
    opacity = offset.dy.abs() / (pageSize.height / 2.0);
  }
  return color.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
}

bool defaultSlideEndHandler(
    {Offset offset, Size pageSize, SlideAxis pageGestureAxis}) {
  if (pageGestureAxis == SlideAxis.both) {
    return offset.distance >
        Offset(pageSize.width, pageSize.height).distance / 3.5;
  } else if (pageGestureAxis == SlideAxis.horizontal) {
    return offset.dx.abs() > pageSize.width / 3.5;
  } else if (pageGestureAxis == SlideAxis.vertical) {
    return offset.dy.abs() > pageSize.height / 3.5;
  }
  return true;
}

double defaultSlideScaleHandler(
    {Offset offset, Size pageSize, SlideAxis pageGestureAxis}) {
  double scale = 0.0;
  if (pageGestureAxis == SlideAxis.both) {
    scale = offset.distance / Offset(pageSize.width, pageSize.height).distance;
  } else if (pageGestureAxis == SlideAxis.horizontal) {
    scale = offset.dx.abs() / (pageSize.width / 2.0);
  } else if (pageGestureAxis == SlideAxis.vertical) {
    scale = offset.dy.abs() / (pageSize.height / 2.0);
  }
  return max(1.0 - scale, 0.8);
}

make sure your page background is transparent #

if you use ExtendedImageSlidePage and slideType =SlideType.onlyImage, make sure your page background is transparent

push with transparent page route #

you should push page with TransparentMaterialPageRoute/TransparentCupertinoPageRoute

  Navigator.push(
    context,
    Platform.isAndroid
        ? TransparentMaterialPageRoute(builder: (_) => page)
        : TransparentCupertinoPageRoute(builder: (_) => page),
  );

Slide Out Page Demo Code 1

Slide Out Page Demo Code 2

Border BorderRadius Shape #

ExtendedImage

parameterdescriptiondefault
borderBoxShape.circle and BoxShape.rectangle,If this is [BoxShape.circle] then [borderRadius] is ignored.-
borderRadiusIf non-null, the corners of this box are rounded by this [BorderRadius].,Applies only to boxes with rectangular shapes; ignored if [shape] is not [BoxShape.rectangle].-
shapeBoxShape.circle and BoxShape.rectangle,If this is [BoxShape.circle] then [borderRadius] is ignored.-
ExtendedImage.network(
  url,
  width: ScreenUtil.instance.setWidth(400),
  height: ScreenUtil.instance.setWidth(400),
  fit: BoxFit.fill,
  cache: true,
  border: Border.all(color: Colors.red, width: 1.0),
  shape: boxShape,
  borderRadius: BorderRadius.all(Radius.circular(30.0)),
),

img

Clear Save #

clear #

to clear disk cached , call clearDiskCachedImages method.

// Clear the disk cache directory then return if it succeed.
///  <param name="duration">timespan to compute whether file has expired or not</param>
Future<bool> clearDiskCachedImages({Duration duration})

to clear disk cached with specific url, call clearDiskCachedImage method.

/// clear the disk cache image then return if it succeed.
///  <param name="url">clear specific one</param>
Future<bool> clearDiskCachedImage(String url) async {

get the local cached image file

Future<File> getCachedImageFile(String url) async {

to clear memory cache , call clearMemoryImageCache method.

///clear all of image in memory
 clearMemoryImageCache();

/// get ImageCache
 getMemoryImageCache() ;

save network #

call saveNetworkImageToPhoto and save image with image_picker_saver

///save netwrok image to photo
Future<bool> saveNetworkImageToPhoto(String url, {bool useCache: true}) async {
  var data = await getNetworkImageData(url, useCache: useCache);
  var filePath = await ImagePickerSaver.saveFile(fileData: data);
  return filePath != null && filePath != "";
}

Show Crop Image #

get your raw image by [Load State](#Load State), and crop image by soureRect.

ExtendedRawImage soureRect is which you want to show image rect.

img

ExtendedRawImage(
  image: image,
  width: num400,
  height: num300,
  fit: BoxFit.fill,
  soucreRect: Rect.fromLTWH(
      (image.width - width) / 2.0, 0.0, width, image.height.toDouble()),
)

crop image demo

Paint #

provide BeforePaintImage and AfterPaintImage callback, you will have the chance to paint things you want.

img

ExtendedImage

parameterdescriptiondefault
beforePaintImageyou can paint anything if you want before paint image.-
afterPaintImageyou can paint anything if you want after paint image.-
  ExtendedImage.network(
    url,
    width: ScreenUtil.instance.setWidth(400),
    height: ScreenUtil.instance.setWidth(400),
    fit: BoxFit.fill,
    cache: true,
    beforePaintImage: (Canvas canvas, Rect rect, ui.Image image) {
      if (paintType == PaintType.ClipHeart) {
        if (!rect.isEmpty) {
          canvas.save();
          canvas.clipPath(clipheart(rect, canvas));
        }
      }
      return false;
    },
    afterPaintImage: (Canvas canvas, Rect rect, ui.Image image) {
      if (paintType == PaintType.ClipHeart) {
        if (!rect.isEmpty) canvas.restore();
      } else if (paintType == PaintType.PaintHeart) {
        canvas.drawPath(
            clipheart(rect, canvas),
            Paint()
              ..colorFilter =
                  ColorFilter.mode(Color(0x55ea5504), BlendMode.srcIn)
              ..isAntiAlias = false
              ..filterQuality = FilterQuality.low);
      }
    },
  );

see paint image demo and push to refresh header which is used in crop image demo

Other APIs #

ExtendedImage

parameterdescriptiondefault
enableMemoryCachewhether cache in PaintingBinding.instance.imageCache)true
clearMemoryCacheIfFailedwhen failed to load image, whether clear memory cache.if ture, image will reload in next time.true

[0.6.4]

  • Issues: Fix issue that rawImageData can't be cached for ExtendedExactAssetImageProvider/ExtendedAssetImageProvider.
  • Improve: Add demo about ImageEditor with native library, it's faster.

[0.6.3]

  • Issues: Fix issue that forget canvas.restore after canvas.clipRect
  • Breaking Change: ImageEditor:you should crop image data before flip or rotate image data now.
  • Improve: Increase cropping speed

[0.6.2]

  • Features: Add InitCropRectType(imageRect,layoutRect) for EditorConfig to define init crop rect base on initial image rect or image layout rect.
  • Breaking Change: Make sure the image is all painted to crop,the fit of image must be BoxFit.contain.

[0.6.1]

  • Issues: Fix issue about drag slowly in ImageEditor

[0.6.0]

  • Issues: Fix issue about strange behaviour at slide out page

[0.5.9]

  • Add HeroBuilderForSlidingPage call back to fix strange hero animation

[0.5.8]

  • Features: Support to crop,rotate,flip image

[0.5.6]

  • Add key for ExtendedImageSlidePage

[0.5.5]

  • Features: Add call back [CanMovePage] for ExtendedImageGesturePageView. related issue

[0.5.4]

  • Issues: Fix issue about borderRadius and border Fix demo error about extended_text

[0.5.3]

  • Improve codes base on v1.7.8

[0.5.1]

  • Features: Add call back [onSlidingPage] when is sliding page, you can change other widgets state in page.[ExtendedImageSlidePage]
  • Add [enableSlideOutPage] parameter to define whether enable slide out page. [ExtendedImage]

[0.4.3]

  • Breaking Change: Parameter [gestureConfig] is obsolete. [initGestureConfigHandler] is used to setting GestureConfig now.

  • Issues: Fix issue about slide page.

  • Features: Support to slide page at loading/failed state

[0.4.2]

  • add README-ZH.md

[0.4.1]

  • add SlideType to support slide only image or whole page[ExtendedImageSlidePage]

[0.4.0]

  • support to slide out page

[0.3.8]

  • update path_provider 1.1.0

[0.3.6]

  • handle loadfailed when re-addListener

[0.3.4]

  • add physics parameter for ExtendedImageGesturePageView

[0.3.3]

  • disabled informationCollector to keep backwards compatibility for now (ExtendedNetworkImageProvider)

[0.3.2]

  • import extended_image_library for network cache

[0.3.1]

  • fix issue that AnimationController.stop() called after AnimationController.dispose().
  • show how to build a double tap scale animation.

[0.2.9]

  • add handleDoubleTap method to support zoom image base on double tap position.

[0.2.8]

  • add inertia scroll when image is zoom in and it's moving page.

[0.2.7]

  • fix issue that wrong behavior of page view scroll when image has big width or big height.

[0.2.6]

  • fix issue that wrong behavior of page view scroll when image is zoom in.

[0.2.5]

  • add onDoubleTap parameter to custom double tap behavior under ExtendedImageMode.Gesture

[0.2.3]

  • add enableMemoryCache parameter, whether cache in PaintingBinding.instance.imageCache
  • add clearMemoryCacheIfFailed parameter, when failed to load image, whether clear memory cache,if ture, image will reload in next time.
  • auto cancel network request is obsolete.

[0.2.2]

  • update path_provider version from 0.4.1 to 0.5.0+1

[0.2.1]

  • add cancelToken,retries,timeLimit and timeRetry parameters for ExtendedImage.network method
  • add default cancelToken for ExtendedImage.network method
  • fix issue about cancel network image request
  • fix gesture page view scrolls not smooth

[0.2.0]

  • support zoom/pan image and view image in page view like wechat(support zoom in and scroll next or previous image)

[0.1.8]

  • remove image_picker_saver from extended_image. obsolete saveNetworkImageToPhoto method(if you want to save photo,you can import image_picker_saver and get data from getNetworkImageData method)

[0.1.7]

  • public instantiateImageCodec method so that you can handle image data by override this in ExtendedNetworkImageProvider

[0.1.6]

  • add getNetworkImageData method

[0.1.5]

  • change toMd5 to keyToMd5

[0.1.4]

  • public imageProvider for ExtendedImageState

[0.1.3]

  • add extended image.

example/README.md

example #

A new Flutter application.

Getting Started #

This project is a starting point for a Flutter application.

A few resources to get you started if this is your first Flutter project:

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  extended_image: ^0.6.4

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:extended_image/extended_image.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
97
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
99
Learn more about scoring.

We analyzed this package on Oct 16, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.1
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Format lib/src/gesture/extended_image_gesture.dart.

Run flutter format to format lib/src/gesture/extended_image_gesture.dart.

Format lib/src/image/extended_render_image.dart.

Run flutter format to format lib/src/image/extended_render_image.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0-dev.68.0 <3.0.0
extended_image_library ^0.1.8 0.1.8
flutter 0.0.0
Transitive dependencies
async 2.4.0
charcode 1.1.2
collection 1.14.11 1.14.12
convert 2.1.1
crypto 2.1.3
http 0.12.0+2
http_client_helper 0.2.1
http_parser 3.1.3
meta 1.1.7
path 1.6.4
path_provider 1.3.1
pedantic 1.8.0+1
platform 2.2.1
sky_engine 0.0.99
source_span 1.5.5
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test