Skip to main content

Enhanced Gradients

Enhance your Flutter gradients with perceptually smoother color transitions by interpolating colors in the HCT (Hue, Chroma, Tone) color space provided by Material Design.

Installation

Add the package to your pubspec.yaml:
dependencies:
  enhanced_gradients: ^2.0.0

Import

import 'package:enhanced_gradients/enhanced_gradients.dart';

Understanding HCT Color System

The HCT color system is part of Material Design 3 and provides a more perceptually uniform way to interpolate between colors compared to traditional RGB or HSL interpolation.
HCT stands for:
  • Hue: The color’s position on the color wheel (0-360 degrees)
  • Chroma: The color’s colorfulness or saturation
  • Tone: The color’s lightness (perceptually uniform)
When you interpolate between colors in HCT space, the transitions appear smoother and more natural to the human eye, especially when transitioning between different hues.

Usage

There are two ways to create enhanced gradients:

1. Extension Method

Use the .enhanced() extension on existing gradient objects:
LinearGradient(
  colors: const [
    Color(0xFF6200EE),
    Color(0xFF03DAC6),
  ],
).enhanced()

2. Enhanced Gradient Classes

Use the dedicated Enhanced*Gradient classes:
EnhancedLinearGradient(
  begin: Alignment.topLeft,
  end: Alignment.bottomRight,
  colors: const [
    Color(0xFF000000),
    Color(0xFFFFFFFF),
  ],
)

Examples

Basic Example

Here’s a simple comparison between a regular gradient and an enhanced gradient:
class GradientComparison extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final colors = [
      Color(0xFF6200EE),
      Color(0xFF03DAC6),
    ];
    
    return Row(
      children: [
        // Regular gradient
        Expanded(
          child: Container(
            height: 200,
            decoration: BoxDecoration(
              gradient: LinearGradient(
                colors: colors,
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter,
              ),
            ),
          ),
        ),
        
        // Enhanced gradient
        Expanded(
          child: Container(
            height: 200,
            decoration: BoxDecoration(
              gradient: LinearGradient(
                colors: colors,
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter,
              ).enhanced(),
            ),
          ),
        ),
      ],
    );
  }
}

Complete Example from Source

The following example demonstrates a gradient comparison tool:
class GradientShowcase extends StatefulWidget {
  @override
  State<GradientShowcase> createState() => _GradientShowcaseState();
}

class _GradientShowcaseState extends State<GradientShowcase> {
  List<Color> _colors = [
    Color(0xFF6200EE),
    Color(0xFF03DAC6),
  ];
  
  @override
  Widget build(BuildContext context) {
    final linearGradient = LinearGradient(
      colors: _colors,
      begin: Alignment.topCenter,
      end: Alignment.bottomCenter,
    );
    
    final radialGradient = RadialGradient(colors: _colors);
    final sweepGradient = SweepGradient(colors: _colors);
    
    return Scaffold(
      body: ListView(
        children: [
          Text(
            'Regular gradient vs Enhanced gradient',
            textAlign: TextAlign.center,
          ),
          // Linear comparison
          _GradientComparison(
            gradientA: linearGradient,
            gradientB: linearGradient.enhanced(),
          ),
          // Radial comparison
          _GradientComparison(
            gradientA: radialGradient,
            gradientB: radialGradient.enhanced(),
          ),
          // Sweep comparison
          _GradientComparison(
            gradientA: sweepGradient,
            gradientB: sweepGradient.enhanced(),
          ),
        ],
      ),
    );
  }
}

Advanced Configuration

Approximation Subdivisions

You can control the smoothness of the gradient by adjusting the approximation subdivisions:
EnhancedLinearGradient(
  colors: colors,
  approximationSubdivisions: 8, // Higher = smoother (default: 6)
)

// Or with extension:
LinearGradient(colors: colors).enhanced(
  approximationSubdivisions: 8,
)
Higher subdivision values create smoother gradients but may impact performance. The default value of 6 provides a good balance.

HctColorTween for Animations

Use HctColorTween instead of ColorTween for smoother color transitions in animations:
class AnimatedColorBox extends StatefulWidget {
  @override
  State<AnimatedColorBox> createState() => _AnimatedColorBoxState();
}

class _AnimatedColorBoxState extends State<AnimatedColorBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Color?> _colorAnimation;
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true);
    
    // Use HctColorTween for smoother transitions
    _colorAnimation = HctColorTween(
      begin: Color(0xFF6200EE),
      end: Color(0xFF03DAC6),
    ).animate(_controller);
  }
  
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _colorAnimation,
      builder: (context, child) {
        return Container(
          width: 200,
          height: 200,
          color: _colorAnimation.value,
        );
      },
    );
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

Visual Comparison

The package includes visual examples showing the difference between regular and enhanced gradients. Here’s what you can expect:
Regular Gradient Issues:
  • May show muddy or grayish transitions between complementary colors
  • Uneven perceived brightness changes
  • Less vibrant intermediate colors
Enhanced Gradient Benefits:
  • Cleaner, more vibrant transitions
  • Perceptually uniform brightness changes
  • More natural-looking color progressions

When to Use Enhanced Gradients

1

Complementary colors

When transitioning between opposite colors on the color wheel (e.g., blue to orange)
2

Multiple color stops

When using gradients with three or more colors
3

Brand colors

When working with specific brand colors that need to look perfect
4

Material Design 3

When building apps following Material Design 3 guidelines

API Reference

Extension Methods

extension EnhancedLinearGradientExtension on LinearGradient {
  LinearGradient enhanced({int? approximationSubdivisions});
}

extension EnhancedRadialGradientExtension on RadialGradient {
  RadialGradient enhanced({int? approximationSubdivisions});
}

extension EnhancedSweepGradientExtension on SweepGradient {
  SweepGradient enhanced({int? approximationSubdivisions});
}

Helper Functions

// Linearly interpolate colors in HCT color space
Color? lerpHct(Color? colorA, Color? colorB, double t);

Performance Considerations

  • Enhanced gradients perform color interpolation during construction
  • The result is cached, so there’s no runtime performance impact
  • Higher approximation subdivisions slightly increase construction time
  • Memory usage is comparable to regular gradients

Source Code

View the source code on GitHub.

Build docs developers (and LLMs) love