image_cropper_widget 1.0.7 copy "image_cropper_widget: ^1.0.7" to clipboard
image_cropper_widget: ^1.0.7 copied to clipboard

A customizable Flutter image cropper widget supporting aspect ratios, rotation, flipping, and custom UI overlay styles.

example/lib/main.dart

import 'dart:typed_data';

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

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Image Cropper Demo',
      debugShowCheckedModeBanner: false,
      home: MyHomePage(title: 'Image Cropper Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 1. Initialize the controller to manage the cropper state
  final _controller = ImageCropperController();
  CropperRatio? _aspectRatio;
  // ignore: unused_field
  Uint8List? _croppedImage;
  HandleType _handleType = HandleType.corner;
  bool _showGrid = true;
  int _gridDivisions = 3;
  CropShape _cropShape = CropShape.rectangle;

  void _cropImage() async {
    // 2. Trigger the crop action
    final Uint8List? bytes = await _controller.crop();
    if (bytes != null) {
      setState(() {
        _croppedImage = bytes;
      });
      if (mounted) {
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            title: const Text('Cropped Image'),
            content: Image.memory(bytes),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Text('Close'),
              ),
            ],
          ),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        actions: [
          IconButton(icon: const Icon(Icons.crop), onPressed: _cropImage),
        ],
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              ImageCropperWidget(
                // 3. Configure the view
                borderRadius: BorderRadius.circular(8.0),
                controller: _controller,
                image: const AssetImage('assets/sample-image.png'),
                aspectRatio: _aspectRatio,
                // 4. Customize the look and feel
                style: CropperStyle(
                  overlayColor: Colors.black54,
                  borderColor: Colors.orange,
                  handlerColor: Colors.deepOrange,
                  borderWidth: 2.0,
                  handlerSize: 30,
                  handleType: _handleType,
                  handlerThickness: 6,
                  showGrid: _showGrid,
                  gridDivisions: _gridDivisions,
                  cropShape: _cropShape,
                ),
                loadingWidget: const Center(child: Text('Loading...')),
              ),
              const SizedBox(height: 16),
              Wrap(
                runSpacing: 6,
                spacing: 6,
                children: CropperRatio.values.map((ratio) {
                  return _AspectRatioButton(
                    label: ratio.label,
                    onPressed: () {
                      // 5. Update aspect ratio programmatically
                      _controller.setAspectRatio(ratio);
                      setState(() => _aspectRatio = ratio);
                    },
                    isSelected: _aspectRatio == ratio,
                  );
                }).toList(),
              ),
              const SizedBox(height: 16),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  IconButton(
                    onPressed: () => _controller.rotateLeft(),
                    icon: const Icon(Icons.rotate_left),
                    tooltip: 'Rotate Left',
                  ),
                  IconButton(
                    onPressed: () => _controller.rotateRight(),
                    icon: const Icon(Icons.rotate_right),
                    tooltip: 'Rotate Right',
                  ),
                  IconButton(
                    onPressed: () => _controller.flipHorizontal(),
                    icon: const Icon(Icons.swap_horiz),
                    tooltip: 'Flip Horizontal',
                  ),
                  IconButton(
                    onPressed: () => _controller.flipVertical(),
                    icon: const Icon(Icons.swap_vert),
                    tooltip: 'Flip Vertical',
                  ),
                ],
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: Row(
                  children: [
                    const SizedBox(width: 20),
                    const Text('Handle Type: '),
                    const SizedBox(width: 10),
                    DropdownButton<HandleType>(
                      value: _handleType,
                      items: HandleType.values.map((type) {
                        return DropdownMenuItem(
                          value: type,
                          child: Text(type.name.toUpperCase()),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) {
                          setState(() {
                            _handleType = value;
                          });
                        }
                      },
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: Row(
                  children: [
                    const SizedBox(width: 20),
                    const Text('Show Grid: '),
                    Switch(
                      value: _showGrid,
                      onChanged: (value) {
                        setState(() {
                          _showGrid = value;
                        });
                      },
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: Row(
                  children: [
                    const SizedBox(width: 20),
                    const Text('Grid Divisions: '),
                    Expanded(
                      child: Slider(
                        value: _gridDivisions.toDouble(),
                        min: 2,
                        max: 10,
                        divisions: 8,
                        label: _gridDivisions.toString(),
                        onChanged: (value) {
                          setState(() {
                            _gridDivisions = value.toInt();
                          });
                        },
                      ),
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: Row(
                  children: [
                    const SizedBox(width: 20),
                    const Text('Crop Shape: '),
                    const SizedBox(width: 10),
                    DropdownButton<CropShape>(
                      value: _cropShape,
                      items: CropShape.values.map((type) {
                        return DropdownMenuItem(
                          value: type,
                          child: Text(type.name.toUpperCase()),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) {
                          setState(() {
                            _cropShape = value;
                          });
                        }
                      },
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 20),
            ],
          ),
        ),
      ),
    );
  }
}

class _AspectRatioButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  final bool isSelected;

  const _AspectRatioButton({
    required this.label,
    required this.onPressed,
    required this.isSelected,
  });

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        backgroundColor: isSelected ? Theme.of(context).primaryColor : null,
        foregroundColor: isSelected ? Colors.white : null,
      ),
      child: Text(label),
    );
  }
}
2
likes
160
points
467
downloads

Publisher

verified publisherinfoowly.com

Weekly Downloads

A customizable Flutter image cropper widget supporting aspect ratios, rotation, flipping, and custom UI overlay styles.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on image_cropper_widget