any_image_view 1.6.0

SDKflutter
Platformandroidioswindowslinuxmacos

A versatile Flutter image viewer supporting PNG, JPG, WebP, GIF, TIFF, RAW, SVG, Lottie, XFile, and cached network images — all in one seamless package.

🖼️ Any Image View

Pub Version Pub Points Pub Likes License Flutter

Any Image View Demo

🎯 Why Choose Any Image View?

Tired of juggling multiple image widgets? Say goodbye to complex image handling! This package gives you one widget that handles everything:

  • Network images with automatic caching and fade animations
  • Local files from your device (XFile & String paths)
  • SVG graphics with perfect scaling and custom placeholders
  • Lottie animations for engaging content (JSON/ZIP)
  • All image formats (PNG, JPG, JPEG, WebP, GIF, TIFF, RAW)
  • Asset images from your app bundle
  • Custom loading states with placeholders
  • Advanced error handling with custom widgets
  • Smooth animations with configurable fade duration
  • Network images with automatic caching and fade animations
  • Pinch-to-zoom and pan support for images.
  • Local files from your device (XFile & String paths)
  • 🛡️ Robust & Reliable - Comprehensive error handling and validation

No more headaches, just beautiful images!


Quick Start (30 seconds)

1️⃣ Add to pubspec.yaml

dependencies:
  any_image_view: ^1.6.0

2️⃣ Run this command

flutter pub get

3️⃣ Copy & Paste this code

import 'package:any_image_view/any_image_view.dart';

// Replace your existing Image widgets with this:
AnyImageView(
imagePath: 'https://picsum.photos/300/200',
height: 200,
width: 300,
borderRadius: BorderRadius.circular(12),
onTap: () => print('Image tapped!'),
)

That's it! You're ready to go! 🎉


📱 Profile Pictures

AnyImageView(
imagePath: user.profileImageUrl,
height: 80,
width: 80,
shape: BoxShape.circle,
border: Border.all(color: Colors.blue, width: 2),
onTap: () => _showProfileDetails(),
)
AnyImageView(
imagePath: galleryItem.url,
height: 200,
width: double.infinity,
boxFit: BoxFit.cover,
borderRadius: BorderRadius.circular(8),
placeholderWidget: Center(
child: CircularProgressIndicator(),
),
errorWidget: Center(
child: Icon(Icons.error, color: Colors.red),
),
)

🎨 SVG Icons & Logos

AnyImageView(
imagePath: 'assets/icons/app_logo.svg',
height: 40,
width: 40,
fit: BoxFit.contain,
placeholderWidget: SizedBox(
height: 40,
width: 40,
child: LinearProgressIndicator(),
),
)

🎬 Lottie Animations

AnyImageView(
imagePath: 'assets/animations/loading.json',
height: 100,
width: 100,
fit: BoxFit.contain,
)

📸 XFile from Image Picker

AnyImageView(
imagePath: pickedFile, // XFile object
height: 250,
width: 250,
borderRadius: BorderRadius.circular(15),
fadeDuration: Duration(milliseconds: 300),
)

📸 Complete Image Picker Integration

Want to let users pick images? Here's the complete solution:

import 'package:image_picker/image_picker.dart';
import 'package:any_image_view/any_image_view.dart';

class ImagePickerScreen extends StatefulWidget {
  @override
  _ImagePickerScreenState createState() => _ImagePickerScreenState();
}

class _ImagePickerScreenState extends State<ImagePickerScreen> {
  XFile? selectedImage;

  Future<void> pickImage() async {
    final ImagePicker picker = ImagePicker();
    final XFile? image = await picker.pickImage(source: ImageSource.gallery);

    setState(() {
      selectedImage = image;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          ElevatedButton(
            onPressed: pickImage,
            child: Text('📷 Pick Image'),
          ),
          SizedBox(height: 20),
          if (selectedImage != null)
            AnyImageView(
              imagePath: selectedImage,
              height: 250,
              width: 250,
              borderRadius: BorderRadius.circular(15),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.2),
                  blurRadius: 10,
                  offset: Offset(0, 5),
                ),
              ],
              fadeDuration: Duration(milliseconds: 500),
              onTap: () => print('Selected image tapped!'),
            ),
        ],
      ),
    );
  }
}

🎨 Advanced Styling Examples

Card-Style Image with Custom Loading

AnyImageView(
imagePath: 'https://example.com/image.jpg',
height: 200,
width: double.infinity,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: Offset(0, 4),
),
],
margin: EdgeInsets.all(16),
placeholderWidget: Container(
height: 200,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(16),
),
child: Center(
child: CircularProgressIndicator(),
),
),
onTap: () => _openImageDetails(),
)

Circular Avatar with Error Handling

AnyImageView(
imagePath: user.avatarUrl,
height: 60,
width: 60,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 3),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 6,
offset: Offset(0, 2),
),
],
errorWidget: Container(
height: 60,
width: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[300],
),
child: Icon(Icons.person, color: Colors.grey[600]),
),
)

Hero Image with Gradient Overlay

Stack(
children: [
AnyImageView(
imagePath: 'assets/images/hero.jpg',
height: 300,
width: double.infinity,
fit: BoxFit.cover,
fadeDuration: Duration(milliseconds: 800),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.transparent, Colors.black.withOpacity(0.7)],
),
),
padding: EdgeInsets.all(16),
child: Text(
'Beautiful Hero Image',
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
),
],
)

🔧 Complete API Reference

Constructor Parameters

ParameterTypeDefaultDescription
imagePathObject?nullString path/URL or XFile object
heightdouble?nullImage container height
widthdouble?nullImage container width
fitBoxFit?BoxFit.coverHow image fits in container
alignmentAlignment?nullImage alignment within container
borderRadiusBorderRadius?nullRounded corners
shapeBoxShapeBoxShape.rectangleRectangle or circle
borderBoxBorder?nullBorder styling
boxShadowList<BoxShadow>?nullShadow effects
marginEdgeInsetsGeometry?nullOuter spacing
paddingEdgeInsetsGeometry?nullInner spacing
onTapVoidCallback?nullTap callback function
errorPlaceHolderString?'assets/images/not_found.png'Fallback image path
placeholderWidgetWidget?nullCustom loading widget
errorWidgetWidget?nullCustom error widget
fadeDurationDuration400msFade animation duration

Supported Image Formats

FormatExtensionDescriptionExample
PNG.pngPortable Network Graphics'assets/images/logo.png'
JPG/JPEG.jpg, .jpegJoint Photographic Experts Group'assets/photos/image.jpg'
WebP.webpWeb Picture format'assets/images/photo.webp'
GIF.gifGraphics Interchange Format'assets/animations/loading.gif'
TIFF.tiffTagged Image File Format'assets/images/document.tiff'
RAW.rawRaw image format'assets/images/photo.raw'
SVG.svgScalable Vector Graphics'assets/icons/icon.svg'
Lottie.json, .zipLottie animations'assets/animations/animation.json'
Networkhttp://, https://HTTP/HTTPS URLs'https://example.com/image.jpg'
XFileXFile objectCross-platform file objectspickedFile

🛡️ Advanced Error Handling

Custom Error Widget

AnyImageView(
imagePath: 'https://broken-link.com/image.jpg',
height: 200,
width: 200,
errorWidget: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 48, color: Colors.red),
SizedBox(height: 8),
Text('Image not available', style: TextStyle(color: Colors.grey[600])),
],
),
),
)

Custom Loading Widget

AnyImageView(
imagePath: 'https://slow-server.com/large-image.jpg',
height: 300,
width: 300,
placeholderWidget: Container(
height: 300,
width: 300,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.grey[300]!, Colors.grey[200]!],
),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 8),
Text('Loading...', style: TextStyle(color: Colors.grey[600])),
],
),
),
),
)

Smooth Fade Animations

AnyImageView(
imagePath: 'https://example.com/image.jpg',
height: 200,
width: 200,
fadeDuration: Duration(milliseconds: 800), // Custom fade duration
onTap: () => print('Image with smooth fade animation'),
)

📱 Platform Support

PlatformStatusFeatures
Android✅ PerfectAll formats & features supported
iOS✅ PerfectAll formats & features supported
Web✅ PerfectAll formats & features supported
macOS✅ PerfectAll formats & features supported
Windows✅ PerfectAll formats & features supported
Linux✅ PerfectAll formats & features supported

🔄 Migration Guide

Before (Multiple widgets needed):

// Network images
CachedNetworkImage(
imageUrl: imageUrl,
height: 200,
width: 200,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)

// Local files
Image.file(
File(filePath),
height: 200,
width: 200,
errorBuilder: (context, error, stackTrace) => Icon(Icons.error),
)

// SVG files
SvgPicture.asset(
'assets/icon.svg',
height: 200,
width: 200,
placeholderBuilder: (context) => CircularProgressIndicator(),
)

After (One widget for all):

// All image types with one widget!
AnyImageView(
imagePath: imageUrl, // or filePath, or asset path, or XFile
height: 200,
width: 200,
placeholderWidget: CircularProgressIndicator(),
errorWidget: Icon(Icons.error),
)

🎯 Pro Tips & Best Practices

1. Performance Optimization

// Always specify dimensions for better performance
AnyImageView(
imagePath: imageUrl,
height: 200,
width: 200, // Specific dimensions improve performance
fit: BoxFit.cover,
)

2. Memory Management

// Use appropriate placeholder sizes for large galleries
AnyImageView(
imagePath: imageUrl,
placeholderWidget: SizedBox(
height: 30,
width: 30,
child: CircularProgressIndicator(strokeWidth: 2),
),
)

3. Accessibility

// Add semantic labels for screen readers
AnyImageView(
imagePath: imageUrl,
onTap: () => _handleTap(),
).semanticsLabel('User profile picture'),
)

4. Custom Animations

// Use longer fade duration for hero images
AnyImageView(
imagePath: heroImageUrl,
fadeDuration: Duration(milliseconds: 1000), // Smooth transition
)

5. Error Recovery

// Provide fallback images for better UX
AnyImageView(
imagePath: userAvatarUrl,
errorPlaceHolder: 'assets/images/default_avatar.png',
errorWidget: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[300],
),
child: Icon(Icons.person),
),
)

🤝 Need Help?


Made with ❤️ by Farhan Sadik Galib

If this package helps you, please consider giving it a ⭐ on Pub.dev