πΌοΈ Any Image View
π― 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 (local assets) with perfect scaling and custom placeholders
- β Lottie animations (local assets) for engaging content (JSON/ZIP)
- β All image formats (PNG, JPG, JPEG, WebP, GIF, TIFF, RAW, HEIC, HEIF, BMP, ICO)
- β Asset images from your app bundle
- β Custom loading states with shimmer animation
- β Advanced error handling with built-in broken_image icon
- β Smooth animations with configurable fade duration
- β Pinch-to-zoom and pan support for images
- β Memory optimization for network images with cache control
- β HTTP headers support for authenticated network requests
- π‘οΈ 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! π
π Popular Use Cases
π± Profile Pictures
AnyImageView(
imagePath: user.profileImageUrl,
height: 80,
width: 80,
shape: BoxShape.circle,
border: Border.all(color: Colors.blue, width: 2),
onTap: () => _showProfileDetails(),
)
πΌοΈ Gallery Images with Custom Loading
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),
),
),
),
],
)
π Advanced Network Image Features
Smart Caching & Memory Optimization
Improved cached_network_image implementation with advanced features:
AnyImageView(
imagePath: 'https://example.com/large-image.jpg',
height: 300, // Automatically used for memory cache optimization
width: 300, // Automatically used for memory cache optimization
// Custom HTTP headers for authenticated requests
httpHeaders: {
'Authorization': 'Bearer your_token_here',
'Custom-Header': 'custom_value',
},
// Advanced caching control
useMemoryCache: true, // Enable in-memory caching
cacheMaxAge: Duration(days: 7), // Cache duration
maxRetryAttempts: 3, // Retry failed requests
// Enhanced error handling
errorWidget: Container(
color: Colors.grey[200],
child: Icon(Icons.error),
),
)
Authenticated Network Images
// Load images with authentication headers
AnyImageView(
imagePath: 'https://api.example.com/user/avatar.jpg',
httpHeaders: {
'Authorization': 'Bearer ${authToken}',
'X-API-Key': apiKey,
},
height: 100,
width: 100,
shape: BoxShape.circle,
)
Memory-Efficient Large Images
// Optimize memory for high-resolution images
// The widget automatically uses height/width for memory cache optimization
AnyImageView(
imagePath: 'https://example.com/4k-image.jpg',
height: 200, // Used for memory cache
width: 300, // Used for memory cache
fit: BoxFit.cover,
)
Retry Logic for Poor Networks
// Automatically retry failed network requests
AnyImageView(
imagePath: 'https://slow-server.com/image.jpg',
maxRetryAttempts: 5, // Retry up to 5 times
placeholderWidget: CircularProgressIndicator(),
errorWidget: Text('Failed to load after retries'),
)
π§ Complete API Reference
Constructor Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
imagePath |
Object? |
null |
String path/URL or XFile object |
height |
double? |
null |
Image container height |
width |
double? |
null |
Image container width |
fit |
BoxFit? |
BoxFit.cover |
How image fits in container |
alignment |
Alignment? |
null |
Image alignment within container |
borderRadius |
BorderRadius? |
null |
Rounded corners |
shape |
BoxShape |
BoxShape.rectangle |
Rectangle or circle |
border |
BoxBorder? |
null |
Border styling |
boxShadow |
List<BoxShadow>? |
null |
Shadow effects |
margin |
EdgeInsetsGeometry? |
null |
Outer spacing |
padding |
EdgeInsetsGeometry? |
null |
Inner spacing |
onTap |
VoidCallback? |
null |
Tap callback function |
placeholderWidget |
Widget? |
null |
Custom loading widget |
errorWidget |
Widget? |
null |
Custom error widget (defaults to broken_image icon) |
fadeDuration |
Duration |
400ms |
Fade animation duration |
enableZoom |
bool |
false |
Enable pinch-to-zoom functionality |
httpHeaders |
Map<String, String>? |
null |
Custom HTTP headers for network images |
cacheMaxAge |
Duration? |
null |
Maximum cache duration for network images |
maxRetryAttempts |
int |
3 |
Max retry attempts for failed requests |
useMemoryCache |
bool |
true |
Enable in-memory caching (uses height/width for cache dimensions) |
Supported Image Formats
| Format | Extension | Description | Example |
|---|---|---|---|
| PNG | .png |
Portable Network Graphics | 'assets/images/logo.png' |
| JPG/JPEG | .jpg, .jpeg |
Joint Photographic Experts Group | 'assets/photos/image.jpg' |
| WebP | .webp |
Web Picture format | 'assets/images/photo.webp' |
| GIF | .gif |
Graphics Interchange Format | 'assets/animations/loading.gif' |
| TIFF | .tiff |
Tagged Image File Format | 'assets/images/document.tiff' |
| RAW | .raw |
Raw image format | 'assets/images/photo.raw' |
| SVG | .svg |
Scalable Vector Graphics | 'assets/icons/icon.svg' |
| Lottie | .json, .zip |
Lottie animations | 'assets/animations/animation.json' |
| Network | http://, https:// |
HTTP/HTTPS URLs | 'https://example.com/image.jpg' |
| XFile | XFile object |
Cross-platform file objects | pickedFile |
π‘οΈ 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
| Platform | Status | Features |
|---|---|---|
| Android | β Perfect | All formats & features supported |
| iOS | β Perfect | All formats & features supported |
| Web | β Perfect | All formats & features supported |
| macOS | β Perfect | All formats & features supported |
| Windows | β Perfect | All formats & features supported |
| Linux | β Perfect | All 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
// Default broken_image icon is shown automatically on error
AnyImageView(
imagePath: userAvatarUrl,
height: 100,
width: 100,
shape: BoxShape.circle,
)
// Or provide a custom error widget for better UX
AnyImageView(
imagePath: userAvatarUrl,
errorWidget: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[300],
),
child: Icon(Icons.person, size: 40),
),
)
π€ Need Help?
- π Found a bug? Report it here
- π‘ Have a feature request? Let me know
- π§ Direct contact: farhansadikgalib@gmail.com
Made with β€οΈ by Farhan Sadik Galib
If this package helps you, please consider giving it a β on Pub.dev