empty_view

A powerful Flutter package for displaying beautiful empty state views with animations, Lottie support, presets, shimmer loading, dark mode, and accessibility features.

pub package License: MIT

Empty View Demo

Features

  • Smart Image Detection - Automatically detects and renders network images, local files, SVG assets, and regular assets
  • Lottie Animation Support - Display beautiful Lottie animations in your empty states
  • Entrance Animations - Smooth fade, slide, scale, and bounce animations
  • Shimmer Skeleton Loading - Show a shimmer placeholder while content loads
  • Dark Mode Support - Automatic theme detection and dark mode styling
  • Accessibility - Built-in semantic labels for screen readers
  • Icon Support - Use Material icons with optional circular backgrounds
  • Secondary Action Button - Add a secondary action alongside the primary button
  • Retry Logic - Built-in retry mechanism with configurable attempts and delays
  • Platform Adaptive - Automatic Cupertino styling on iOS, Material on Android
  • Prebuilt Presets - Ready-to-use empty states for common scenarios (16 total!)
  • Highly Customizable - Extensive styling options via EmptyViewStyle
  • Gradient Backgrounds - Beautiful gradient background support (NEW in v2.1)
  • Builder Pattern - Custom layouts with EmptyView.builder() (NEW in v2.1)
  • Animation Callbacks - onAnimationComplete for post-animation actions (NEW in v2.1)
  • Custom Error Widgets - Replace error icons with custom widgets (NEW in v2.1)

Installation

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

dependencies:
  empty_view: ^2.1.0

Then run:

flutter pub get

Quick Start

import 'package:empty_view/empty_view.dart';

// Basic usage
EmptyView(
  title: 'No Items Found',
  description: 'There are no items to display at the moment.',
  buttonText: 'Refresh',
  onButtonTap: () => fetchItems(),
)

// Using presets (recommended for common scenarios)
EmptyViewPresets.noInternet(onRetry: () => checkConnection())
EmptyViewPresets.emptyCart(onShopNow: () => navigateToShop())
EmptyViewPresets.noSearchResults(searchTerm: 'shoes')

Usage Examples

Using Prebuilt Presets

The easiest way to use empty_view is with the prebuilt presets:

// No internet connection
EmptyViewPresets.noInternet(
  onRetry: () => checkConnection(),
)

// Empty shopping cart
EmptyViewPresets.emptyCart(
  onShopNow: () => navigateToShop(),
)

// No search results
EmptyViewPresets.noSearchResults(
  searchTerm: 'flutter widgets',
  onClearSearch: () => clearSearch(),
)

// Error state
EmptyViewPresets.error(
  message: 'Failed to load data',
  onRetry: () => fetchData(),
)

// Other available presets:
EmptyViewPresets.noNotifications()
EmptyViewPresets.noMessages(onNewMessage: () {})
EmptyViewPresets.noFavorites(onBrowse: () {})
EmptyViewPresets.noData(onRefresh: () {})
EmptyViewPresets.locationRequired(onEnableLocation: () {})
EmptyViewPresets.maintenance()
EmptyViewPresets.noOrders(onStartShopping: () {})
EmptyViewPresets.noFiles(onUpload: () {})

With Icon

EmptyView(
  icon: Icons.inbox_outlined,
  iconColor: Colors.grey,
  iconSize: 80,
  title: 'No Messages',
  description: 'Your inbox is empty.',
  buttonText: 'Compose',
  onButtonTap: () => composeMessage(),
)

With Icon Background

EmptyView(
  icon: Icons.cloud_off,
  iconColor: Colors.blue,
  iconSize: 80,
  showIconBackground: true,
  iconBackgroundColor: Colors.blue.shade50,
  title: 'Offline Mode',
  description: 'You are currently offline.',
)

With Lottie Animation

EmptyView(
  lottiePath: 'assets/animations/empty.json', // or network URL
  lottieRepeat: true,
  title: 'Nothing Here',
  description: 'Check back later for new content!',
  buttonText: 'Refresh',
  onButtonTap: () => refresh(),
)

With Entrance Animation

EmptyView(
  icon: Icons.star,
  title: 'Animated Entry',
  description: 'Watch this smooth animation!',
  enableAnimation: true,
  animationType: EmptyViewAnimation.slideUp, // fadeIn, slideDown, scale, bounce
  animationDuration: Duration(milliseconds: 800),
  animationCurve: Curves.easeOutCubic,
)

Shimmer Skeleton Loading

// Using the factory constructor
EmptyView.skeleton()

// Or with custom colors
EmptyView.skeleton(
  shimmerBaseColor: Colors.grey.shade300,
  shimmerHighlightColor: Colors.grey.shade100,
)

// Toggle between shimmer and content
isLoading ? EmptyView.skeleton() : EmptyView(
  icon: Icons.check,
  title: 'Data Loaded',
  description: 'Content is now available.',
)

With Secondary Button

EmptyView(
  icon: Icons.error_outline,
  title: 'Something Went Wrong',
  description: 'We encountered an error loading your data.',
  buttonText: 'Try Again',
  onButtonTap: () => retry(),
  secondaryButtonText: 'Contact Support',
  onSecondaryButtonTap: () => openSupport(),
)

With Retry Logic

EmptyView(
  icon: Icons.refresh,
  title: 'Connection Failed',
  description: 'Automatic retry with up to 3 attempts.',
  onRetry: () async {
    // This will be called automatically with retries
    await fetchData();
  },
  buttonText: 'Retry',
  maxRetries: 3,
  retryDelay: Duration(seconds: 2),
)

Platform Adaptive Styling

EmptyView(
  icon: Icons.phone_iphone,
  title: 'Platform Adaptive',
  description: 'Uses Cupertino on iOS, Material on Android.',
  buttonText: 'Continue',
  onButtonTap: () {},
  adaptive: true, // Enables platform-specific styling
)

Custom Styling

EmptyView(
  imagePath: 'https://example.com/image.png',
  title: 'Fully Customizable',
  description: 'Customize every aspect of the empty view.',
  buttonText: 'Custom Button',
  onButtonTap: () {},
  style: EmptyViewStyle(
    titleStyle: TextStyle(
      fontSize: 24,
      fontWeight: FontWeight.bold,
      color: Colors.indigo,
    ),
    descriptionStyle: TextStyle(
      fontSize: 16,
      color: Colors.grey,
    ),
    buttonColor: Colors.indigo,
    buttonTextColor: Colors.white,
    buttonBorderRadius: 25,
    buttonHeight: 56,
    imageWidthFactor: 0.4,
    imageHeightFactor: 0.25,
    horizontalPadding: 32,
  ),
)

Using Style Presets

// Dark mode optimized
EmptyView(
  description: 'Dark mode style',
  style: EmptyViewStyle.dark(),
)

// Minimal spacing
EmptyView(
  description: 'Minimal style',
  style: EmptyViewStyle.minimal(),
)

// Compact for small spaces
EmptyView(
  description: 'Compact style',
  style: EmptyViewStyle.compact(),
)

// Spacious with more padding
EmptyView(
  description: 'Spacious style',
  style: EmptyViewStyle.spacious(),
)

// Pill-shaped buttons
EmptyView(
  description: 'Rounded style',
  style: EmptyViewStyle.rounded(),
)

Animation Types

Animation Description
EmptyViewAnimation.none No animation
EmptyViewAnimation.fadeIn Simple fade in effect
EmptyViewAnimation.slideUp Slide up with fade
EmptyViewAnimation.slideDown Slide down with fade
EmptyViewAnimation.scale Scale up with fade
EmptyViewAnimation.bounce Bounce effect with elastic curve

EmptyView Properties

Property Type Default Description
title String? - Title text
description String Required Description text
imagePath String? - Path to image (auto-detected type)
icon IconData? - Icon to display
iconColor Color? - Icon color
iconSize double 80 Icon size
showIconBackground bool false Show circular background for icon
iconBackgroundColor Color? - Icon background color
lottiePath String? - Path to Lottie animation
lottieRepeat bool true Repeat Lottie animation
lottieReverse bool false Reverse on repeat
buttonText String? - Primary button text
onButtonTap VoidCallback? - Primary button callback
isLoading bool false Show loading on button
secondaryButtonText String? - Secondary button text
onSecondaryButtonTap VoidCallback? - Secondary button callback
isSecondaryLoading bool false Show loading on secondary button
onRetry Future<void> Function()? - Retry callback with auto-retry
maxRetries int 3 Maximum retry attempts
retryDelay Duration 2 seconds Delay between retries
enableAnimation bool true Enable entrance animation
animationType EmptyViewAnimation fadeIn Animation type
animationDuration Duration 600ms Animation duration
animationCurve Curve easeOutCubic Animation curve
showShimmer bool false Show shimmer skeleton
shimmerBaseColor Color? - Shimmer base color
shimmerHighlightColor Color? - Shimmer highlight color
semanticLabel String? - Accessibility label
adaptive bool false Use platform-adaptive styling
style EmptyViewStyle? - Custom style configuration
customImage Widget? - Custom image widget
customButton Widget? - Custom button widget
errorIcon IconData broken_image Icon when image fails
errorIconSize double 60 Error icon size

EmptyViewStyle Properties

Property Type Default Description
titleStyle TextStyle? Theme default Title text style
descriptionStyle TextStyle? Theme default Description text style
titleColor Color? Theme color Title color
descriptionColor Color? Theme color Description color
buttonColor Color? Primary color Button background color
buttonTextColor Color? OnPrimary color Button text color
secondaryButtonColor Color? Primary color Secondary button color
secondaryButtonTextColor Color? - Secondary button text color
imageWidthFactor double 0.5 Image width as screen fraction
imageHeightFactor double 0.3 Image height as screen fraction
horizontalPadding double 24.0 Horizontal padding
imageBottomSpacing double 16.0 Spacing below image
titleBottomSpacing double 12.0 Spacing below title
descriptionBottomSpacing double 16.0 Spacing below description
buttonVerticalPadding double 24.0 Vertical padding around button
buttonHorizontalPadding double 32.0 Horizontal padding around button
buttonBorderRadius double 12.0 Button border radius
buttonHeight double 50.0 Button height
buttonSpacing double 8.0 Spacing between buttons
buttonElevation double 0.0 Button elevation
iconSizeFactor double 1.0 Icon size multiplier
iconBackgroundColor Color? - Icon container background
iconContainerPadding double 16.0 Icon container padding

Presets Reference

Preset Icon Default Title
noInternet wifi_off No Internet Connection
emptyCart shopping_cart Your Cart is Empty
noSearchResults search_off No Results Found
noNotifications notifications_off No Notifications
noMessages message No Messages
noFavorites favorite_border No Favorites Yet
error error_outline Something Went Wrong
noData inbox No Data Available
locationRequired location_off Location Required
maintenance construction Under Maintenance
noOrders receipt_long No Orders Yet
noFiles folder_off No Files
permissionDenied lock_outline Permission Required (NEW)
sessionExpired timer_off Session Expired (NEW)
emptyTimeline timeline No Activity Yet (NEW)
noPaymentMethods credit_card_off No Payment Methods (NEW)

Dark Mode

The package automatically detects dark mode and adjusts colors accordingly. You can also use the dark style preset:

EmptyView(
  description: 'Optimized for dark mode',
  style: EmptyViewStyle.dark(
    buttonColor: Colors.tealAccent,
  ),
)

Accessibility

The package includes built-in accessibility support:

EmptyView(
  title: 'Empty State',
  description: 'No items available',
  // Custom semantic label for screen readers
  semanticLabel: 'The list is empty. Tap refresh to load items.',
  buttonText: 'Refresh',
  onButtonTap: () {},
)

New in v2.1

Gradient Backgrounds

EmptyView(
  icon: Icons.star,
  description: 'Beautiful gradient background',
  style: EmptyViewStyle.gradient(
    gradient: LinearGradient(
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
      colors: [Colors.purple.shade100, Colors.blue.shade100],
    ),
  ),
)

Builder Pattern for Custom Layouts

EmptyView.builder(
  description: 'Custom layout with builder',
  builder: (context, style) => Column(
    children: [
      Container(
        padding: EdgeInsets.all(24),
        decoration: BoxDecoration(
          color: Colors.blue.shade50,
          shape: BoxShape.circle,
        ),
        child: Icon(Icons.rocket_launch, size: 64, color: Colors.blue),
      ),
      SizedBox(height: 16),
      Text('Launch your app!', style: TextStyle(fontSize: 18)),
    ],
  ),
  buttonText: 'Get Started',
  onButtonTap: () {},
)

Animation Completion Callback

EmptyView(
  icon: Icons.check_circle,
  description: 'Animation completed!',
  onAnimationComplete: () {
    // Trigger actions after animation finishes
    loadData();
  },
)

Custom Error Widget

EmptyView(
  imagePath: 'https://example.com/image.png',
  description: 'With custom error widget',
  errorWidget: Column(
    children: [
      Icon(Icons.cloud_off, size: 64, color: Colors.grey),
      Text('Image unavailable'),
    ],
  ),
)

Migration Guide

From v1.x to v2.x

The package is fully backward compatible. All v1.x code works without changes:

// v1.x code still works in v2.x
EmptyView(
  imagePath: 'assets/empty.png',
  title: 'No Items',
  description: 'Nothing to show.',
  buttonText: 'Refresh',
  onButtonTap: () {},
)

From v2.0 to v2.1

v2.1 is fully backward compatible with v2.0. New features are opt-in:

// v2.0 code works in v2.1
EmptyView(
  icon: Icons.inbox,
  title: 'No Items',
  description: 'Nothing to show.',
  enableAnimation: true,
  animationType: EmptyViewAnimation.slideUp,
)

// New v2.1 features (optional)
EmptyView(
  icon: Icons.inbox,
  title: 'No Items',
  description: 'Nothing to show.',
  onAnimationComplete: () => print('Ready!'), // NEW
  style: EmptyViewStyle(
    backgroundGradient: LinearGradient(...), // NEW
  ),
)

Example

Check out the example folder for a complete sample app demonstrating all features.

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a PR.

License

MIT License - see the LICENSE file for details.

Libraries

empty_view
A powerful Flutter package for displaying beautiful empty state views with animations, Lottie support, presets, shimmer loading, dark mode, and accessibility features.