stretchable_image 0.0.1 copy "stretchable_image: ^0.0.1" to clipboard
stretchable_image: ^0.0.1 copied to clipboard

A Flutter widget that horizontally stretches the center area of an image while keeping the left and right edges visually intact. Useful for chat bubbles, resizable panels, and border-like images.

stretchable_image #

A Flutter widget that horizontally stretches the center area of an image while keeping the left and right edges visually intact. This is especially useful for:

  • Chat bubbles
  • Resizable panels / cards
  • Border-like images that need to adapt to dynamic width #

    Features #

  • Split image into three parts: left / center (stretch area) / right
  • Only center area is stretched or cropped horizontally
  • Pixel-perfect with device pixel ratio handling
  • Flexible sizing:
    • Fixed size via size
    • Or automatically adapts to parent constraints when size is null #

      Installation #

      Add this to your pubspec.yaml:
      dependencies:
      stretchable_image: ^0.1.0
    
    Then run:
    
      flutter pub get
    
    ---
    ## Usage
    ### 1. Basic usage (fixed size)
    
    ### 2. Auto size from parent constraints (no `size` given)
    When `size` is `null`, the widget will:
    
  • Use LayoutBuilder to read parent constraints
  • Fill the available width/height if bounded
  • Fall back to the image’s intrinsic size if unbounded
import 'package:stretchable_image/stretchable_image.dart';

class BasicExample extends StatelessWidget {
  const BasicExample({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: StretchableImage(
        image: AssetImage('assets/border.png'),
        size: Size(200, 40),
      ),
    );
  }
}

3. Custom stretch area ratio #

centerStretchAreaRatio controls how wide the stretchable center area is (relative to the whole image width). It must be less than 1.0.

class CustomStretchAreaExample extends StatelessWidget {
  const CustomStretchAreaExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: const [
        Text('Center stretch ratio = 0.3'),
        SizedBox(height: 8),
        StretchableImage(
          image: AssetImage('assets/border.png'),
          size: Size(200, 40),
          centerStretchAreaRatio: 0.3,
        ),
        SizedBox(height: 16),
        Text('Center stretch ratio = 0.6'),
        SizedBox(height: 8),
        StretchableImage(
          image: AssetImage('assets/border.png'),
          size: Size(200, 40),
          centerStretchAreaRatio: 0.6,
        ),
      ],
    );
  }
}

Example from this package #

The example app (example/lib/main.dart) can look like this:

  import 'package:flutter/material.dart';
import 'package:stretchable_image/stretchable_image.dart';

void main() {
  runApp(const StretchableImageExampleApp());
}

class StretchableImageExampleApp extends StatelessWidget {
  const StretchableImageExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'StretchableImage Example',
      home: const StretchableImageDemoPage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class StretchableImageDemoPage extends StatelessWidget {
  const StretchableImageDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    const double height = 40;
    return Scaffold(
      appBar: AppBar(
        title: const Text('StretchableImage Demo'),
      ),
      body: Center(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: const [
              Text(
                'border.png as background. '
                    'Show how the image behaves with different widths.',
                textAlign: TextAlign.center,
              ),
              SizedBox(height: 24),
              Text('Narrow (compressed, middle area may be clipped)'),
              SizedBox(height: 8),
              StretchableImage(
                image: AssetImage('assets/border.png'),
                size: Size(80, height),
              ),
              SizedBox(height: 24),
              Text('Normal width (close to original aspect)'),
              SizedBox(height: 8),
              StretchableImage(
                image: AssetImage('assets/border.png'),
                size: Size(160, height),
              ),
              SizedBox(height: 24),
              Text('Wide (middle area is stretched)'),
              SizedBox(height: 8),
              StretchableImage(
                image: AssetImage('assets/border.png'),
                size: Size(260, height),
              ),
              SizedBox(height: 24),
              Text('Extra wide (strong stretch in the middle)'),
              SizedBox(height: 8),
              StretchableImage(
                image: AssetImage('assets/border.png'),
                size: Size(360, height),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

API #

  class StretchableImage extends StatefulWidget {
  /// Source image.
  final ImageProvider image;
  /// Stretch area ratio, must be less than 1.0. Default is 0.5.
  ///
  /// The image is conceptually split into three parts:
  ///   [ left | center | right ]
  /// where:
  ///   - `center` width = `centerStretchAreaRatio * imageWidth`
  ///   - `left` and `right` share the remaining width equally
  ///
  /// When the widget is stretched horizontally:
  ///   - `center` area is stretched
  ///   - `left` and `right` keep their visual shape
  ///
  /// When the widget is compressed horizontally:
  ///   - `center` area is cropped first
  ///   - `left` and `right` are preserved as much as possible
  final double centerStretchAreaRatio;
  /// Target size.
  ///
  /// - If provided, [StretchableImage] will paint with this size exactly.
  /// - If null, the widget will expand to the constraints from its parent
  ///   (using [LayoutBuilder]) and use that as the painting size.
  final Size? size;
  const StretchableImage({
  Key? key,
  required this.image,
  this.size,
  this.centerStretchAreaRatio = 0.5,
  });
  }

Screenshot #

Example with different target widths (using border.png): [StretchableImage example] Make sure you place the screenshot in your repository, for example: example/screenshots/screenshot.png. #

Example project #

This package includes a full Flutter example app under the example/ directory. Run it with:

  cd example
  flutter pub get
  flutter run

The example demonstrates:

  • Fixed width vs auto width
  • Different centerStretchAreaRatio values
  • Behavior when the widget is stretched and compressed #

    Design & implementation notes #

  • The widget internally splits the source image horizontally into three regions:
    • left (A)
    • center (H, the stretchable area)
    • right (A)
  • Height is scaled uniformly according to target height.
  • Horizontally, depending on the target width:
    1. Stretch: if target ≥ “natural” width, only center is stretched.
    2. Crop center: if target is smaller but still wide enough to keep left & right, the center is gradually cropped.
    3. Uniform scale: if even left & right cannot fit, the image degenerates to A-A and everything is uniformly scaled down. This behavior makes it suitable for images with “linear” center design (e.g. flat background, simple gradients) where stretching the middle part does not break the visual style. #

      License #

      MIT License. See LICENSE for details.
2
likes
0
points
18
downloads

Publisher

verified publishermars-ai.net

Weekly Downloads

A Flutter widget that horizontally stretches the center area of an image while keeping the left and right edges visually intact. Useful for chat bubbles, resizable panels, and border-like images.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on stretchable_image