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.

Overview

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.

Web demo for ExtendedImage

Table of contents

Import

  • null-safety
environment:
  sdk: '>=2.12.0 <3.0.0'
  flutter: '>=2.0'
dependencies:
  extended_image: ^4.0.0
  • non-null-safety

1.22.6 to 2.0, Flutter Api has breaking change,please use non-null-safety if you under 1.22.6.

environment:
  sdk: '>=2.6.0 <2.12.0'
  flutter: '>1.17.0 <=1.22.6'
dependencies:
  extended_image: ^3.0.0-non-null-safety

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();
parameter description default
url The URL from which the image will be fetched. required
scale The scale to place in the [ImageInfo] object of the image. 1.0
headers The HTTP headers that will be used with [HttpClient.get] to fetch image from network. -
cache whether cache image to local false
retries the time to retry to request 3
timeLimit time limit to request image -
timeRetry the time duration to retry to request milliseconds: 100
cancelToken token to cancel network request CancellationToken()

you can create new provider and extends it with ExtendedProvider, and override instantiateImageCodec method. so that you can handle image raw data here (compress image).

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 true for network and others are false) to true

img

Notice:

  • if you don't want to override any state, please return null in this case

  • if you want to override size or sourceRect, you can override it with ExtendedRawImage at completed state

  • if you want to add something (like animation) at completed state, you can override it with ExtendedImageState.completedWidget

  • ExtendedImageState.completedWidget is include gesture or editor, so that you would't miss them

/// 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/method description default
extendedImageInfo image info -
extendedImageLoadState LoadState(loading,completed,failed) -
returnLoadStateChangedWidget if this is true, return widget which from LoadStateChanged function immediately(width/height/gesture/border/shape etc, will not effect on it) -
imageProvider ImageProvider -
invertColors invertColors -
imageStreamKey key of image -
reLoadImage() if image load failed,you can reload image by call it -
completedWidget return completed widget include gesture or editor -
loadingProgress return the loading progress for network image (ImageChunkEvent ) -
abstract class ExtendedImageState {
  void reLoadImage();
  ImageInfo get extendedImageInfo;
  LoadState get extendedImageLoadState;

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

  ImageProvider get imageProvider;

  bool get invertColors;

  Object get imageStreamKey;

  Widget get completedWidget;
}

demo code

[ 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; } }, ) ">
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;

      ///if you don't want override completed widget
      ///please return null or state.completedWidget
      //return null;
      //return state.completedWidget;
      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

parameter description default
mode image mode (none, gesture, editor) none
initGestureConfigHandler init GestureConfig when image is ready,for example, base on image width/height -
onDoubleTap call back of double tap under ExtendedImageMode.gesture -
extendedImageGestureKey you can handle zoom/pan by using this key manually -

GestureConfig

parameter description default
minScale min scale 0.8
animationMinScale the min scale for zooming then animation back to minScale when scale end minScale _ 0.8
maxScale max scale 5.0
animationMaxScale the max scale for zooming then animation back to maxScale when scale end maxScale _ 1.2
speed speed for zoom/pan 1.0
inertialSpeed inertial speed for zoom/pan 100
cacheGesture save Gesture state (for example in ExtendedImageGesturePageView, gesture state will not change when scroll back),remember clearGestureDetailsCache at right time false
inPageView whether in ExtendedImageGesturePageView false
initialAlignment init image rect with alignment when initialScale > 1.0 InitialAlignment.center
hitTestBehavior How to behave during hit tests HitTestBehavior.deferToChild
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,
        initialAlignment: InitialAlignment.center,
        );
  },
)

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

parameter description default
mode image mode (none,gestrue,editor) none
initEditorConfigHandler init EditorConfig when image is ready. -
extendedImageEditorKey key of ExtendedImageEditorState to flip/rotate/get crop rect -

EditorConfig

parameter description default
maxScale max scale of zoom 5.0
cropRectPadding the padding between crop rect and image layout rect. EdgeInsets.all(20.0)
cornerSize size of corner shape (DEPRECATED! Use cornerPainter) Size(30.0, 5.0)
cornerColor color of corner shape (DEPRECATED! Use cornerPainter) primaryColor
lineColor color of crop line scaffoldBackgroundColor.withOpacity(0.7)
lineHeight height of crop line 0.6
editorMaskColorHandler call back of editor mask color base on pointerDown scaffoldBackgroundColor.withOpacity(pointerDown ? 0.4 : 0.8)
hitTestSize hit test region of corner and line 20.0
animationDuration auto center animation duration Duration(milliseconds: 200)
tickerDuration duration to begin auto center animation after crop rect is changed Duration(milliseconds: 400)
cropAspectRatio aspect ratio of crop rect null(custom)
initCropRectType init crop rect base on initial image rect or image layout rect imageRect
cornerPainter corner shape ExtendedImageCropLayerPainterNinetyDegreesCorner()
hitTestBehavior How to behave during hit tests HitTestBehavior.deferToChild

crop aspect ratio

it's a double value, so it's easy 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 layer painter

you can define your crop layer by override [EditorConfig.editorCropLayerPainter].

class EditorCropLayerPainter {
  const EditorCropLayerPainter();
  void paint(Canvas canvas, Size size, ExtendedImageCropLayerPainter painter) {
    paintMask(canvas, size, painter);
    paintLines(canvas, size, painter);
    paintCorners(canvas, size, painter);
  }

  /// draw crop layer corners
  void paintCorners(
      Canvas canvas, Size size, ExtendedImageCropLayerPainter painter) {
  }

  /// draw crop layer lines
  void paintMask(
      Canvas canvas, Size size, ExtendedImageCropLayerPainter painter) {
  }
  

  /// draw crop layer lines
  void paintLines(
      Canvas canvas, Size size, ExtendedImageCropLayerPainter painter) {
  } 
}

crop,flip,reset

  • add key for ExtendedImageEditorState

    final GlobalKey editorKey =GlobalKey ();

  • 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 library 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

parameter description default
cacheGesture whether should move page true

GestureConfig

parameter description default
cacheGesture save Gesture state (for example in ExtendedImageGesturePageView, gesture state will not change when scroll back),remember clearGestureDetailsCache at right time false
inPageView whether in ExtendedImageGesturePageView false
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

parameter description default
enableSlideOutPage whether enable slide out page false
heroBuilderForSlidingPage build Hero only for sliding page, the transform of sliding page must be working on Hero,so that Hero animation wouldn't be strange when pop page null

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

parameter description default
child The [child] contained by the ExtendedImageGesturePage. -
slidePageBackgroundHandler build background when slide page defaultSlidePageBackgroundHandler
slideScaleHandler customize scale of page when slide page defaultSlideScaleHandler
slideEndHandler call back of slide end,decide whether pop page defaultSlideEndHandler
slideAxis axis of slide(both,horizontal,vertical) SlideAxis.both
resetPageDuration reset page position when slide end(not pop page) milliseconds: 500
slideType slide whole page or only image SlideType.onlyImage
onSlidingPage call back when it's sliding page, change other widgets state on page as you want -
slideOffsetHandler customize offset when slide page -
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

parameter description default
border BoxShape.circle and BoxShape.rectangle,If this is [BoxShape.circle] then [borderRadius] is ignored. -
borderRadius If 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]. -
shape BoxShape.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.

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

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

clear specific one Future clearDiskCachedImage(String url) async { ">
/// clear the disk cache image then return if it succeed.
///  clear specific one
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 network 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 sourceRect.

ExtendedRawImage sourceRect is which you want to show image rect.

img

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

Paint

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

img

ExtendedImage

parameter description default
beforePaintImage you can paint anything if you want before paint image. -
afterPaintImage you 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

MemoryUsage

You can reduce memory usage with following settings now.

  • ExtendedResizeImage
parameter description default
[ExtendedResizeImage.compressionRatio] The images size will resize to original * [compressionRatio].It's ExtendedResizeImages first pick.The compressionRatio`s range is from 0.0 (exclusive), to 1.0 (exclusive). null
[ExtendedResizeImage.maxBytes] [ExtendedResizeImage] will compress the image to a size that is smaller than [maxBytes]. The default size is 500KB. 500 << 10
[ExtendedResizeImage.width]/[ExtendedResizeImage.height] The width/height the image should decode to and cache. It's same as [ResizeImage], null
    ExtendedImage.network(
      'imageUrl',  
      compressionRatio: 0.1,
      maxBytes: null,
      cacheWidth: null,
      cacheHeight: null,  
    )

    ExtendedImage(
      image: ExtendedResizeImage(
        ExtendedNetworkImageProvider(
          'imageUrl',  
        ),
        compressionRatio: 0.1,
        maxBytes: null,
        width: null,
        height: null,
      ),
    )
  • clearMemoryCacheWhenDispose
parameter description default
clearMemoryCacheWhenDispose It's not good enough after Flutter 2.0, it seems that we can't release memory usage if this image is not completed(https://github.com/fluttercandies/extended_image/issues/317). It will release memory usage only for completed image now. false
   ExtendedImage.network(
     'imageUrl',     
     clearMemoryCacheWhenDispose: true,
   )
  • imageCacheName
parameter description default
imageCacheName The name of [ImageCache], you can define custom [ImageCache] to store this image. In this way you can work with them without affecting other [ImageCache] null
   ExtendedImage.network(
     'imageUrl',  
     imageCacheName: 'MemoryUsage',
   )
     
  /// clear when this page is disposed   
  @override
  void dispose() {
    // clear ImageCache which named 'MemoryUsage'
    clearMemoryImageCache(imageCacheName);
    super.dispose();
  }   

Other APIs

ExtendedImage

parameter description default
enableMemoryCache whether cache in PaintingBinding.instance.imageCache) true
clearMemoryCacheIfFailed when failed to load image, whether clear memory cache.if true, image will reload in next time. true
clearMemoryCacheWhenDispose when image is removed from the tree permanently, whether clear memory cache. false
Comments
  • build error in flutter 1.10.15, ExtendedMemoryImageProvider.load' has fewer positional arguments than those of overridden method 'MemoryImage.load'.

    build error in flutter 1.10.15, ExtendedMemoryImageProvider.load' has fewer positional arguments than those of overridden method 'MemoryImage.load'.

    pub.flutter-io.cn/extended_image_library-0.1.8/lib/src/extended_me mory_image_provider.dart:12:24: Error: The method 'ExtendedMemoryImageProvider.load' has fewer positional arguments than those of overridden method 'MemoryImage.load'. ImageStreamCompleter load(MemoryImage key) {

    flutter sdk build error 
    opened by mana-ai 25
  • 不能正常加载图片

    不能正常加载图片

    控制台一直循环打印这句话

    Invalid argument (onError): Error handler must accept one Object or one Object and a StackTrace as arguments, and return a a valid result: Closure: () => Null
    

    图片是正常的有效链接

    开始是正常的,后来想升级flutter2.0.3,无奈太多的插件不兼容又回退版本,然后就出现图片不能加载出来的问题

    opened by mdddj 23
  • can't be assigned to the parameter type 'ImageStreamListener

    can't be assigned to the parameter type 'ImageStreamListener

    . Dart VM version: 2.3.1 . Flutter 1.7.2-pre.30 • channel master

    ..../extended_image-0.4.1/lib/src/extended_imag e.dart:723:59: Error: The argument type 'void Function(ImageInfo, bool)' can't be assigned to the parameter type 'ImageStreamListener'.

    opened by jeson-jin 22
  • 1.17.0 Error: No named parameter with the name 'animation'.

    1.17.0 Error: No named parameter with the name 'animation'.

    Compiler message: /Users/xxxx/flutter/.pub-cache/hosted/pub.dartlang.org/extended_image-0.7.2/lib/src/gesture/extended_image_slide_page_route.dart:333:9: Error: No named parameter with the name 'animation'. animation: animation, ^^^^^^^^^ /Users/xxxx/flutter/packages/flutter/lib/src/cupertino/route.dart:435:3: Context: Found this candidate, but the arguments don't match. CupertinoFullscreenDialogTransition({ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    FAILURE: Build failed with an exception.

    [✓] Flutter (Channel master, v1.16.4-pre.38, on Mac OS X 10.15.3 19D76, locale zh-Hans-CN)
    
    opened by crazecoder 19
  • 内存回收问题

    内存回收问题

    final provider = ExtendedNetworkImageProvider(listSourceRepository[index].imageUrl);
    provider.evict().then((result) {
        if (result) {
            print("回收成功");
        } else {
           print("回收失败");
       }
    })
    

    测试了很多遍,都是回收失败

    opened by OHeroJ 18
  • can't clone a disposed image

    can't clone a disposed image

    使用场景: 图片列表页 点击图片=>图片放大预览页。

    情况1: 如果图片列表页每一项图片都使用ExtendedImage.network来展示,点击跳转图片放大页面(传参是图片的url)后正常。

    情况2: 如果图片列表页不使用使用ExtendedImage.network来展示,首次点击跳转图片放大页面正常,关闭后再次点击报错can't clone a disposed image。

    情况3: 如果图片列表页每一项图片都使用ExtendedImage.network来展示,点击跳转图片放大页面(传参不是图片的原始url,比如加了url参数时间戳),则出现情况2的现象。

    图片放大预览页基础代码:

    ExtendedImageSlidePage(
            key: slidePagekey,
            child: GestureDetector(
                child: ExtendedImage.network(
                    widget.url,
                    enableSlideOutPage: true,
                    mode: ExtendedImageMode.gesture,
                    ///make hero better when slide out
                    heroBuilderForSlidingPage: (Widget result) {
                        return Hero(
                            tag: widget.url,
                            child: result,
                            flightShuttleBuilder: (BuildContext flightContext,
                                Animation<double> animation,
                                HeroFlightDirection flightDirection,
                                BuildContext fromHeroContext,
                                BuildContext toHeroContext) {
                            final Hero hero = (flightDirection == HeroFlightDirection.pop
                                ? fromHeroContext.widget
                                : toHeroContext.widget) as Hero;
                            return hero.child;
                            },
                        );
                    },
                ),
                onTap: () {
                    slidePagekey.currentState.popPage();
                    Navigator.pop(context);
                },
            ),
            slideAxis: SlideAxis.both,
            slideType: SlideType.onlyImage,
        )
    

    大概猜测和图片缓存有关 但不知道怎么解

    bug 
    opened by 826327700 17
  • MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider)

    MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider)

    请问在我的flutter_module中包含有extended_image插件的使用,然后将flutter_module嵌套进iOS原生项目里,运行时控制台在运行到使用到缓存图片的地方时打印如下信息 ,flutter: MissingPluginException(No implementation found for method getTemporaryDirectory on channel plugins.flutter.io/path_provider)

    opened by OmgKevin 16
  • Exception thrown in Flutter v1.5.9-pre.106/1.5.9-pre.107

    Exception thrown in Flutter v1.5.9-pre.106/1.5.9-pre.107

    Error:

    Error: The argument type 'Null Function(StringBuffer)' can't be assigned to the parameter type 'Iterable Function()'.

    • 'StringBuffer' is from 'dart:core'.
    • 'Iterable' is from 'dart:core'.
    • 'DiagnosticsNode' is from 'package:flutter/src/foundation/diagnostics.dart' ('file:///Users/thinkdigital/development/flutter/packages/flutter/lib/src/foundation/diagnostics.dart'). Try changing the type of the parameter, or casting the argument to 'Iterable Function()'. informationCollector: (StringBuffer information) { ^

    this points to the file in "package:extended_image/src/network/extended_network_image_provider.dart" line: 68

    opened by ThinkDigitalSoftware 16
  • slideOutPage dragging offset has no effect

    slideOutPage dragging offset has no effect

    Widget _buildImageView(String url) {
        Widget result = new ExtendedImage.network(
          url,
          cache: true,
          mode: ExtendedImageMode.gesture,
          enableSlideOutPage: true,
          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);
          },
          fit: BoxFit.fitHeight,
          borderRadius: BorderRadius.circular(25),
          border: Border.all(color: Colors.red, width: 1.0),
          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;
          },
          loadStateChanged: (ExtendedImageState state) {
            switch (state.extendedImageLoadState) {
              case LoadState.loading:
                _controller.reset();
                return Container(
                  width: 200,
                  height: 250,
                  padding: EdgeInsets.only(left: 200),
                  child: SpinKitCircle(
                    color: globalMainChatColor,
                    size: 40,
                  ),
                );
                break;
              case LoadState.completed:
                _controller.forward();
                return FadeTransition(
                    opacity: _controller,
                    child: Container(
                      margin: EdgeInsets.only(top: 8),
                      width: max(state.extendedImageInfo.image.width * 0.25, 200),
                      height: max(state.extendedImageInfo.image.height * 0.2, 250),
                      child: null,
                      decoration: BoxDecoration(
                          image: DecorationImage(
                              image: state.imageProvider, fit: BoxFit.cover),
                          borderRadius: BorderRadius.only(
                              topLeft: Radius.circular(20.0),
                              topRight: Radius.circular(20.0),
                              bottomLeft: Radius.circular(20.0),
                              bottomRight: Radius.circular(5.0))),
                    ));
                break;
              case LoadState.failed:
                _controller.reset();
                return GestureDetector(
                  child: Stack(
                    fit: StackFit.expand,
                    children: <Widget>[
                      Image.asset(
                        "assets/images/failed.jpg",
                        fit: BoxFit.fill,
                      ),
                      Positioned(
                        bottom: 0.0,
                        left: 0.0,
                        right: 0.0,
                        child: Text(
                          "加载失败,点击重试",
                          textAlign: TextAlign.center,
                        ),
                      )
                    ],
                  ),
                  onTap: () {
                    state.reLoadImage();
                  },
                );
                break;
            }
          },
        );
        return ExtendedImageSlidePage(
          child: result,
          slideAxis: SlideAxis.both,
          slideType: SlideType.onlyImage,
          onSlidingPage: (state) {
            ///you can change other widgets' state on page as you want
          },
          slideEndHandler: (offset) {
            var pageSize = MediaQuery.of(context).size;
            return offset.distance >
                Offset(pageSize.width, pageSize.height).distance / 1.5;
          },
        );
      }
    

    I changed the value to bigger or smaller, doesn't have any effect on sliding offset, I want it as small as possible rather than drag the whole distance of screen and then trigger slide out.\

    Any idea?

    opened by jinfagang 15
  • Swipe gestures are conflicting with zoom gestures

    Swipe gestures are conflicting with zoom gestures

    I use the latest version of Extended Image (1.2.0), flutter 1.22. Tried both on physical and simulator.

    1. Sometimes swipe left/right gesture doesn't work. Open image from gallery. Try to swipe it right or left with a huge velocity.

    Expected results: image is being changed to the next one. Actual results: image is being closed like I swiped up or down.

    1. When image is zoomed in, it's too easy to accidentally close or swipe it. Open any image and zoom it. Then, try to move your zoom by swiping it up/down or left/right.

    Expected results: zoomed image should move with my gestures Actual results: image is closed or changed to another one.

    My code: https://github.com/Zchandev/iChan/blob/master/lib/pages/gallery_item_page.dart#L81

    wontfix 
    opened by Zchandev 14
  • Implement circular crop

    Implement circular crop

    First of all thank you publish this library but We need circular crop feature inside this library. Can you suggest me how can we implement this feature in our production app because we need it asap.

    invalid 
    opened by prasantco 14
  • Is making two simultaneous requests to ExtendedImage.network for the same image bad?

    Is making two simultaneous requests to ExtendedImage.network for the same image bad?

    I have created a FutureBuilderthat will get a network image and display it. But I also need image dimensions for a separate process. So I have created two separate futures which will work in the FutureBuilder:

    FutureBuilder

            FutureBuilder<List>(
              future: Future.wait([
                getImageWidget(image:widget.image, width:widget.width, height:widget.height),
                _calculateImageDimension(image:widget.image),
              ]),
    

    Future 1: Retrieve the image

    Future<Widget> getImageWidget({image, width, height})
    {
    return ExtendedImage.network(...)
    }
    
    

    Future 2: Get the image dimensions

    Future<Size> _calculateImageDimension({image}) {
      Completer<Size> completer = Completer();
      Image image = Image(image: ExtendedNetworkImageProvider(imgixedImage, cache: true));
      image.image.resolve(const ImageConfiguration()).addListener(
        ImageStreamListener(
              (ImageInfo image, bool synchronousCall) {
            var myImage = image.image;
            Size size = Size(myImage.width.toDouble(), myImage.height.toDouble());
            completer.complete(size);
          },
        ),
      );
      return completer.future;
    }
    

    I believe both of these futures are called simultaneously on the same image. I do not want to make two separate network requests for the same image, I was hoping one will go first and save the image in the cache and then the second one will just use the image retrieved from the cache.

    Is ExtendedNetworkImage smart enough to deal with two simultaneous requests? Or is there a chance that there will be two separate downloads of the same image?

    opened by mark8044 2
  • Flutter Web does not support the blend mode: BlendMode.clear

    Flutter Web does not support the blend mode: BlendMode.clear

    Hi.

    Version 6.3.3 introduces drawing editor with BlendMode.clear which is not supported for the flutter web.

    Trying to use editor in the latest version produces error:

    "Flutter Web does not support the blend mode: BlendMode.clear"

    and Editor is unusable.

    Version 6.3.2 is of course working fine.

    opened by Cyb0org 2
  • Getting this error while compiling to web Error: The argument type 'File/*1*/' can't be assigned to the parameter type 'File/*2*/'.

    Getting this error while compiling to web Error: The argument type 'File/*1*/' can't be assigned to the parameter type 'File/*2*/'.

    While compiling for web, I am getting this error. This code was working previously and I recently updated extended image version to the latest from 4.1.0 after which this issue cropped if. If I comment out the kIsWeb check and removed ExtendedImage.file code, it works fine for web, but with this check, it fails. Appreciate if anyone can help me out

    Error: The argument type 'File/1/' can't be assigned to the parameter type 'File/2/'.

    • 'File/1/' is from 'dart:io'.
    • 'File/2/' is from 'package:extended_image_library/src/_platform_web.dart' ('../flutter/.pub-cache/hosted/pub.dartlang.org/extended_image_library-3.4.1/lib/src/_platform_web.dart').

    Even though I am checking if it is for web, I am still getting this error. The code is as follow

      `Column(
          children: <Widget>[
            Expanded(
              child: kIsWeb
                  ? ExtendedImage.network(
                      _resetToOriginalImage
                          ? widget.orgImgFile as String
                          : widget.imgFile as String,
                      fit: BoxFit.contain,
                      mode: ExtendedImageMode.editor,
                      extendedImageEditorKey: editorKey,
                      initEditorConfigHandler: (ExtendedImageState? state) {
                        return EditorConfig(
                            maxScale: 8.0,
                            cropLayerPainter: _cropLayerPainter!,
                            cropAspectRatio: _aspectRatio!.value);
                      },
                      cacheRawData: true,
                    )
    
                  // TODO: this doesn't allow to compile to web. Check if this is resolved in new version of extended image package
                  : ExtendedImage.file(
                      _resetToOriginalImage
                          ? widget.orgImgFile as File
                          : widget.imgFile as File,
                      fit: BoxFit.contain,
                      mode: ExtendedImageMode.editor,
                      enableLoadState: true,
                      extendedImageEditorKey: editorKey,
                      initEditorConfigHandler: (ExtendedImageState? state) {
                        return EditorConfig(
                            maxScale: 8.0,
                            cropLayerPainter: _cropLayerPainter!,
                            cropAspectRatio: _aspectRatio!.value);
                      },
                      cacheRawData: true,
                    ),
            ),
          ],
        ),`
    

    Found another reference for this issue logged in recently https://github.com/dint-dev/universal_io/issues/17#issuecomment-1327377845

    Let me know if any more information is needed.

    Thanks

    opened by tanveer1302 0
  • [Build Error Android] Error: Too few positional arguments: 4 required, 3 given.

    [Build Error Android] Error: Too few positional arguments: 4 required, 3 given.

    Hi, I migrated the flutter to the master channel: 3.6.0-4.0.pre.32 and the Android build failing :( with error:

    ../../../AppData/Local/Pub/Cache/hosted/pub.dev/extended_image-7.0.0-dev.1/lib/src/gesture/page_view/widgets/scroll_activity.dart:56:12: Error: Too few positional arguments: 4 required, 3 given.
      ) : super(
               ^
    Target kernel_snapshot failed: Exception
    
    
    FAILURE: Build failed with an exception.
    
    * Where:
    Script 'C:\tools\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 1151
    
    * What went wrong:
    Execution failed for task ':app:compileFlutterBuildDebug'.
    > Process 'command 'C:\tools\flutter\bin\flutter.bat'' finished with non-zero exit value 1
    
    * Try:
    > Run with --stacktrace option to get the stack trace.
    > Run with --info or --debug option to get more log output.
    > Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 14s
    Running Gradle task 'assembleDebug'...                             15.2s
    Exception: Gradle task assembleDebug failed with exit code 1
    

    error2

    Please help me to fix this issue, thanks in advance!

    flutter sdk build error 
    opened by RoyalCoder88 1
  • [Safari]Long press gesture does not work in safari browser

    [Safari]Long press gesture does not work in safari browser

    I want to save the picture by long pressing the picture. But in Safari, when I zoom the image, the long press gesture is not recognized properly. How can I solve it please?

    It is worth noting that the html rendering mode should be selected. --web-renderer html

    Steps:

    1. Zoom the image
    2. Long press the picture
    Code sample
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key key}) : super(key: key);
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      String get url => 'https://photo.tuchong.com/4870004/f/298584322.jpg';
    
      void showSheet() {
        showModalBottomSheet(
          context: context,
          builder: (BuildContext context) {
            return Container(
              height: 240,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Expanded(
                    child: Text('保存'),
                  ),
                  Divider(height: 1),
                  Divider(
                    height: 0.5,
                  ),
                  Expanded(child: Text('取消')),
                ],
              ),
            );
          },
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
              Expanded(
                child: GestureDetector(
                  onLongPress: () {
                    showSheet();
                  },
                  child: ExtendedImage.network(
                    url,
                    fit: BoxFit.contain,
                    cache: true,
                    // border: Border.all(color: Colors.red, width: 5.0),
                    // shape: boxShape,
                    mode: ExtendedImageMode.gesture,
                    // borderRadius: const BorderRadius.all(Radius.circular(30.0)),
                  ),
                ),
              ),
            ],
          ),
        );
      }
    }
    
    Logs
    ~ flutter doctor -v                
    [✓] Flutter (Channel stable, 3.0.4, on macOS 12.2.1 21D62 darwin-arm, locale
        zh-Hans-CN)
        • Flutter version 3.0.4 at /Users/ones-wy/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 85684f9300 (4 months ago), 2022-06-30 13:22:47 -0700
        • Engine revision 6ba2af10bb
        • Dart version 2.17.5
        • DevTools version 2.12.2
    
    [✓] Android toolchain - develop for Android devices (Android SDK version
        32.1.0-rc1)
        • Android SDK at /Users/ones-wy/Library/Android/sdk
        • Platform android-32, build-tools 32.1.0-rc1
        • ANDROID_HOME = /Users/ones-wy/Library/Android/sdk
        • ANDROID_SDK_ROOT = /Users/ones-wy/Library/Android/sdk
        • Java binary at: /Applications/Android
          Studio.app/Contents/jre/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 13.3)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • CocoaPods version 1.11.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 2021.1)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)
    
    [✓] VS Code (version 1.67.1)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.52.0
    
    [✓] Connected device (3 available)
        • 21091116C (mobile) • rcguam4h759pt4jn • android-arm64  • Android 11 (API
          30)
        • macOS (desktop)    • macos            • darwin-arm64   • macOS 12.2.1
          21D62 darwin-arm
        • Chrome (web)       • chrome           • web-javascript • Google Chrome
          100.0.4896.75
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    opened by OnesWYong 1
Releases(v1.12.13+1)
Owner
FlutterCandies
Custom Flutter candies (packages) for you to build your Flutter app easily. Enjoy it!
FlutterCandies
An image editor with crop, scribble, mosaic, add-text, flip, rotated functions.

image_editor_dove A high-performance image editor with crop, scribble, mosaic, add-text, flip, rotated functions. Support custom ui style. drawing rot

null 27 Dec 16, 2022
A Flutter image editor with support for paint, text, filters, emojis, stickers and more

Flutter Image Editor Plugin with simple, easy support for image editing using Paints, Text, Filters, Emoji and Sticker like stories.

null 44 Dec 22, 2022
Loading indicator GIFs. Material and Cupertino (Android and iOS) loading indicators in assorted sizes. Use as placeholders for loading remote image assets. Demo: https://gallery.codelessly.com/flutterwebsites/loadinggifs/

Loading GIFs High quality Android and iOS loading spinners. View Demo Loading GIFs is a collection of high fidelity loading animations in GIF format.

Codelessly 31 Dec 23, 2022
Flutter BlurHash - Compact representation of a placeholder for an image.

Compact representation of a placeholder for an image. Encode a blurry image under 30 caracters for instant display like used by Medium. Maintainer: @Solido

Flutter Community 408 Dec 30, 2022
a package for flutter canvas paint dash line path easily.

dash_painter a package for flutter canvas paint dash line path easily. 1. DashPainter 如何使用 DashPainter 只负责对 路径 Path 的虚线化绘制,不承担组件职能。 一般用在拥有 Canvas 对象的回

FlutterCandies 22 Oct 9, 2022
Crop any widget/image in Android, iOS, Web and Desktop with fancy and customizable UI, in pure Dart code.

crop A Flutter package for cropping any widget, not only images. This package is entirely written in Dart and supports Android, iOS, Web and Desktop.

Mahdi 225 Jan 6, 2023
A simple and easy flutter demo to crop image

flutter_image_crop A simple demo to crop image on flutter easily. A Chinese version of this document can be found here Flutter_image_crop Plugin will

路小飞 3 Jul 8, 2021
A flutter plugin which provides Crop Widget for cropping images.

A flutter plugin which provides Crop Widget for cropping images. crop_your_image provides only minimum UI for deciding cropping area inside images. Other UI parts, such as "Crop" button or "Change Aspect Ratio" button, need to be prepared by each app developers.

Chooyan 96 Dec 31, 2022
Download, cache and show images in a flutter app

Cached network image A flutter library to show images from the internet and keep them in the cache directory. How to use The CachedNetworkImage can be

Baseflow 2.1k Jan 3, 2023
Generic cache manager for flutter

flutter_cache_manager A CacheManager to download and cache files in the cache directory of the app. Various settings on how long to keep a file can be

Rene Floor 6 Jul 19, 2021
A flutter carousel widget, support infinite scroll, and custom child widget.

carousel_slider A carousel slider widget. Features Infinite scroll Custom child widgets Auto play Supported platforms Flutter Android Flutter iOS Flut

serenader 1.4k Dec 30, 2022
Flutter package for Image Carousel It is an image carousel widget.

Snapshot Carousel Flutter package for Image Carousel It is an image carousel widget. Supported platforms Flutter Android Flutter iOS Flutter web Flutt

Mrigank Anand 12 Jun 3, 2021
A scrollable, dismissable by swiping, zoomable, rotatable image gallery on which you can add a dynamic overlay.

Swipe Image Gallery A scrollable, dismissable by swiping, zoomable, rotatable image gallery on which you can add a dynamic overlay. While it is intend

null 20 Dec 7, 2022
FMS2 provides Dart implementation of the core design aspects of the UML state diagrams.

FSM2 provides an implementation of the core design aspects of the UML2 state diagrams. FMS2 supports: Nested States Concurrent Regions Guard Condition

Brett Sutton 46 Sep 28, 2022
Generate & add your custom icons

The custom icons will be converted into a ttf font file, which will be added into the project. An automatically generated Dart file will be added, allowing icons to be used like Icon(CustomIcons.email)

Firgia 8 Nov 23, 2022
A Flutter widget that paints an image and moves it at a slower speed than the main scrolling content.

A Flutter widget that paints an image and moves it at a slower speed than the main scrolling content. Installation Add dependency to your pubspec.yaml

Anatoly Pulyaevskiy 272 Dec 23, 2022
Flutter plugin that allows you to display multi image picker on iOS and Android. 👌🔝🎉

IMPORTANT: This repository has been archived and no longer mantained. As I don't have time anymore to work on the package it became very outdated. For

Radoslav Vitanov 898 Apr 29, 2021
Image caching system for flutter

image_cacheing image_cacheing is an image caching package. It is currently tested for Android applications. ImageCacheing widget takes url as a param.

evolving_kid 3 May 31, 2021
A flutter tool to generate beautiful code snippets in the form of an image.

A flutter tool to generate beautiful code snippets in the form of an image.

Mahesh Jamdade 4 Jan 18, 2022