πΌοΈ 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 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! π
π 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),
),
),
),
],
)
π§ 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 |
errorPlaceHolder |
String? |
'assets/images/not_found.png' |
Fallback image path |
placeholderWidget |
Widget? |
null |
Custom loading widget |
errorWidget |
Widget? |
null |
Custom error widget |
fadeDuration |
Duration |
400ms |
Fade animation duration |
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
// 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?
- π 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