image

31 Dec 2025

9K

35K

Creating an Image Picker Widget with Cropping in Flutter

Modern mobile applications often require users to select and customize images, whether it's for a profile picture, a product listing, or a document upload. Flutter provides robust packages to handle image picking and advanced image manipulation like cropping. This article will guide you through creating a reusable image picker widget in Flutter that includes a cropping feature, ensuring a professional and user-friendly experience.

Why Image Picking with Cropping?

While picking an image from the gallery or camera is straightforward, users frequently need to adjust the image to fit specific aspect ratios or to focus on a particular area. Implementing cropping functionality directly within your app enhances user control and reduces the need for external photo editing, leading to a smoother user journey.

Prerequisites and Dependencies

To implement an image picker with cropping, we'll leverage two powerful Flutter packages:

  • image_picker: Provides a platform-agnostic way to pick images from the device's image library or camera.
  • image_cropper: Offers a customizable UI for cropping images.

Add these dependencies to your pubspec.yaml file:


dependencies:
  flutter:
    sdk: flutter
  image_picker: ^1.1.2 # Use the latest version
  image_cropper: ^5.0.1 # Use the latest version

After adding the dependencies, run flutter pub get.

Platform-Specific Setup

Both packages require minimal platform-specific configuration:

Android

No extra permissions are usually required in AndroidManifest.xml for image_picker to access the gallery. If you plan to use the camera, ensure you have:


<uses-permission android:name="android.permission.CAMERA" />

For image_cropper, ensure your android/app/build.gradle file's minSdkVersion is 21 or higher:


android {
    defaultConfig {
        minSdkVersion 21
    }
}

iOS

Add the following keys to your ios/Runner/Info.plist file:


<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to your photo library to pick images.</string>
<key>NSCameraUsageDescription</key>
<string>This app needs access to your camera to take photos.</string>

Core Logic: Picking and Cropping an Image

Let's first understand how to pick and then crop an image before encapsulating it into a widget.

1. Picking an Image

Using ImagePicker, you can pick an image from the gallery or camera:


import 'package:image_picker/image_picker.dart';

Future<XFile?> pickImageFromGallery() async {
  final ImagePicker picker = ImagePicker();
  final XFile? pickedFile = await picker.pickImage(source: ImageSource.gallery);
  return pickedFile;
}

2. Cropping the Image

Once you have an XFile (which contains the path to the selected image), you can pass its path to ImageCropper:


import 'package:image_cropper/image_cropper.dart';
import 'package:flutter/material.dart'; // For Colors

Future<CroppedFile?> cropImage(String imagePath) async {
  final croppedFile = await ImageCropper().cropImage(
    sourcePath: imagePath,
    aspectRatioPresets: [
      CropAspectRatioPreset.square,
      CropAspectRatioPreset.ratio3x2,
      CropAspectRatioPreset.original,
      CropAspectRatioPreset.ratio4x3,
      CropAspectRatioPreset.ratio16x9
    ],
    uiSettings: [
      AndroidUiSettings(
        toolbarTitle: 'Crop Image',
        toolbarColor: Colors.deepPurple,
        toolbarWidgetColor: Colors.white,
        initAspectRatio: CropAspectRatioPreset.original,
        lockAspectRatio: false,
      ),
      IOSUiSettings(
        title: 'Crop Image',
      ),
    ],
  );
  return croppedFile;
}

The aspectRatioPresets define common aspect ratios available to the user. uiSettings allow you to customize the look and feel of the cropper UI for both Android and iOS platforms, ensuring it matches your app's theme.

Creating the Reusable Image Picker Widget

Now, let's combine these functionalities into a single, reusable StatefulWidget.

This widget will:

  • Provide a button to trigger the image picking and cropping process.
  • Display the selected and cropped image.
  • Offer a callback to return the final File object of the cropped image to its parent widget.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image_cropper/image_cropper.dart';

class ImageCropperPicker extends StatefulWidget {
  /// Callback function that returns the cropped image File.
  final Function(File)? onImagePicked;

  /// Text to display on the pick image button.
  final String buttonText;

  /// Initial image to display if any.
  final File? initialImage;

  const ImageCropperPicker({
    Key? key,
    this.onImagePicked,
    this.buttonText = "Pick & Crop Image",
    this.initialImage,
  }) : super(key: key);

  @override
  State<ImageCropperPicker> createState() => _ImageCropperPickerState();
}

class _ImageCropperPickerState extends State<ImageCropperPicker> {
  File? _selectedImage;

  @override
  void initState() {
    super.initState();
    _selectedImage = widget.initialImage;
  }

  Future<void> _pickAndCropImage() async {
    final ImagePicker picker = ImagePicker();
    // You can also add ImageSource.camera for taking new photos
    final XFile? pickedFile = await picker.pickImage(source: ImageSource.gallery);

    if (pickedFile != null) {
      final croppedFile = await ImageCropper().cropImage(
        sourcePath: pickedFile.path,
        aspectRatioPresets: [
          CropAspectRatioPreset.square,
          CropAspectRatioPreset.ratio3x2,
          CropAspectRatioPreset.original,
          CropAspectRatioPreset.ratio4x3,
          CropAspectRatioPreset.ratio16x9
        ],
        uiSettings: [
          AndroidUiSettings(
            toolbarTitle: 'Crop Image',
            toolbarColor: Colors.deepPurple,
            toolbarWidgetColor: Colors.white,
            initAspectRatio: CropAspectRatioPreset.original,
            lockAspectRatio: false,
          ),
          IOSUiSettings(
            title: 'Crop Image',
          ),
        ],
      );

      if (croppedFile != null) {
        setState(() {
          _selectedImage = File(croppedFile.path);
        });
        widget.onImagePicked?.call(_selectedImage!);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        GestureDetector(
          onTap: _pickAndCropImage,
          child: Container(
            width: 150,
            height: 150,
            decoration: BoxDecoration(
              color: Colors.grey[200],
              border: Border.all(color: Colors.grey),
              borderRadius: BorderRadius.circular(8.0),
            ),
            child: _selectedImage != null
                ? ClipRRect(
                    borderRadius: BorderRadius.circular(8.0),
                    child: Image.file(
                      _selectedImage!,
                      width: 150,
                      height: 150,
                      fit: BoxFit.cover,
                    ),
                  )
                : const Center(
                    child: Icon(
                      Icons.add_a_photo,
                      color: Colors.grey,
                      size: 50,
                    ),
                  ),
          ),
        ),
        const SizedBox(height: 10),
        ElevatedButton(
          onPressed: _pickAndCropImage,
          child: Text(widget.buttonText),
        ),
        if (_selectedImage != null) ...[
          const SizedBox(height: 10),
          Text(
            'Image selected!',
            style: TextStyle(color: Colors.green[700]),
          ),
        ]
      ],
    );
  }
}

Using the Widget

Integrating the ImageCropperPicker into your application is straightforward:


import 'dart:io';
import 'package:flutter/material.dart';
// Assuming ImageCropperPicker is in 'image_cropper_picker.dart'
import 'package:your_app_name/image_cropper_picker.dart'; // Adjust path accordingly

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  File? _userProfileImage;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile Picture Setup'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Upload your profile picture:',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            const SizedBox(height: 30),
            ImageCropperPicker(
              buttonText: 'Choose Profile Image',
              initialImage: _userProfileImage, // Pass initial image if available
              onImagePicked: (File image) {
                setState(() {
                  _userProfileImage = image;
                });
                // Here you can upload the 'image' file to a server,
                // save its path, or display it elsewhere in your app.
                print('Picked and cropped image path: ${image.path}');
              },
            ),
            const SizedBox(height: 30),
            if (_userProfileImage != null)
              CircleAvatar(
                radius: 60,
                backgroundImage: FileImage(_userProfileImage!),
              )
            else
              const CircleAvatar(
                radius: 60,
                child: Icon(Icons.person, size: 60),
              ),
          ],
        ),
      ),
    );
  }
}

// Example main function to run the app
void main() {
  runApp(MaterialApp(
    home: HomePage(),
  ));
}

Conclusion

By integrating image_picker and image_cropper, you can create a highly functional and aesthetically pleasing image selection widget for your Flutter applications. This reusable component not only streamlines your development process but also provides a superior user experience by allowing users to precisely crop their images directly within the app. Remember to always consider platform-specific configurations and user permissions for a smooth deployment.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is