My Media Module
Một package Flutter đơn giản để xử lý hình ảnh và video với API trực quan, dễ sử dụng. Package này giúp đơn giản hóa các tác vụ phức tạp như chọn ảnh từ thư viện, chụp ảnh từ camera, cắt ảnh và quản lý các file media.
Tính năng chính
- ✨ Chọn ảnh/video từ thư viện hoặc camera
- 🖼️ Hỗ trợ chọn nhiều ảnh cùng lúc
- ✂️ Cắt và chỉnh sửa ảnh với nhiều tùy chọn
- 📱 Xem trước media với widget có thể tùy chỉnh
- 🔒 Tự động xử lý quyền truy cập (camera, thư viện ảnh)
- 🧩 API đơn giản, dễ tích hợp
Cài đặt
Thêm vào pubspec.yaml:
dependencies:
media_module:
git:
url: https://github.com/Cat1m/media_module.git
ref: main # hoặc tag cụ thể
Sử dụng cơ bản
Khởi tạo controller
final _mediaController = MediaController();
Chọn ảnh từ thư viện
try {
final result = await _mediaController.pickMedia(
MediaOptions.gallery(
allowMultiple: true,
imageQuality: 80,
),
);
if (result != null && result.isNotEmpty) {
// Xử lý ảnh đã chọn
setState(() {
_selectedMedia.addAll(result);
});
}
} catch (e) {
// Xử lý lỗi
print('Lỗi chọn ảnh: $e');
}
Chụp ảnh từ camera
try {
final result = await _mediaController.pickMedia(
MediaOptions.camera(
imageQuality: 90,
cropOptions: const CropOptions(
aspectRatio: CropAspectRatio.square,
),
),
);
if (result != null && result.isNotEmpty) {
setState(() {
_selectedMedia.addAll(result);
});
}
} catch (e) {
print('Lỗi chụp ảnh: $e');
}
Sử dụng MediaPickerButton
MediaPickerButton(
text: 'Chọn Media',
icon: Icons.add_photo_alternate,
options: const MediaOptions(
allowMultiple: true,
imageQuality: 80,
),
controller: _mediaController,
showBottomSheet: true,
onMediaSelected: (media) {
setState(() {
_selectedMedia.addAll(media);
});
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Lỗi: ${error.message}')),
);
},
)
Cắt ảnh đã chọn
final croppedImage = await _mediaController.cropImage(
_selectedMedia[index],
const CropOptions(
aspectRatio: CropAspectRatio.square,
uiOptions: CropUIOptions(toolbarTitle: 'Chỉnh sửa ảnh'),
),
);
if (croppedImage != null) {
setState(() {
_selectedMedia[index] = croppedImage;
});
}
Hiển thị ảnh với MediaPreview
MediaPreview(
mediaItem: _selectedMedia[index],
borderRadius: BorderRadius.circular(8),
showDeleteButton: true,
onDelete: () {
setState(() {
_selectedMedia.removeAt(index);
});
},
)
Cấu hình quyền truy cập và thư viện
Android
Thêm vào file AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Cấu hình Image Cropper cho Android
- Thêm UCropActivity vào AndroidManifest.xml:
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Ucrop.CropTheme"/>
- Thêm style cho Ucrop vào file
android/app/src/main/res/values/styles.xml:
<resources>
<!-- Các style khác của bạn -->
<style name="Ucrop.CropTheme" parent="Theme.AppCompat.Light.NoActionBar"/>
</resources>
- Tạo file mới
android/app/src/main/res/values-v35/styles.xmlđể hỗ trợ Android 15 (Edge-to-Edge mode):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Ucrop.CropTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
</resources>
iOS
Thêm vào file Info.plist:
<key>NSCameraUsageDescription</key>
<string>Ứng dụng cần quyền truy cập camera để chụp ảnh</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Ứng dụng cần quyền truy cập thư viện ảnh để chọn hình ảnh</string>
<key>NSMicrophoneUsageDescription</key>
<string>Ứng dụng cần quyền truy cập microphone để quay video</string>
Cấu hình Image Cropper cho iOS
Image Cropper trên iOS không yêu cầu cấu hình bổ sung. Tính năng này sử dụng thư viện TOCropViewController và sẽ hoạt động ngay sau khi package được cài đặt.
Web
Cấu hình Image Cropper cho Web
Để hỗ trợ cắt ảnh trên web, thêm các thẻ script và css vào file web/index.html trong thẻ <head>:
<head>
<!-- Các thẻ khác của bạn -->
<!-- cropperjs -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.js"></script>
<!-- Các thẻ khác của bạn -->
</head>
Lưu ý: Để sử dụng cropper trên web, bạn cần đảm bảo luôn cung cấp
WebUiSettingstronguiSettingscủa options.
Tùy chọn nâng cao
Tùy chỉnh CropOptions
CropOptions(
aspectRatio: CropAspectRatio.ratio16x9,
maxWidth: 1920,
maxHeight: 1080,
uiOptions: CropUIOptions(
toolbarTitle: 'Tùy chỉnh ảnh',
toolbarColor: Colors.black,
toolbarTextColor: Colors.white,
activeControlsColor: Colors.blue,
doneButtonText: 'Xong',
cancelButtonText: 'Hủy',
),
)
Ví dụ chi tiết về cắt ảnh
Dưới đây là ví dụ đầy đủ về cách sử dụng cropImage với các cấu hình UI khác nhau cho từng nền tảng:
final croppedImage = await _mediaController.cropImage(
selectedImage,
CropOptions(
maxWidth: 1080,
maxHeight: 1080,
aspectRatio: CropAspectRatio.square,
uiOptions: CropUIOptions(
toolbarTitle: 'Chỉnh sửa ảnh',
toolbarColor: Colors.deepOrange,
toolbarTextColor: Colors.white,
activeControlsColor: Colors.blue,
doneButtonText: 'Hoàn tất',
cancelButtonText: 'Hủy bỏ',
),
),
);
if (croppedImage != null) {
setState(() {
// Cập nhật ảnh đã cắt
_selectedMedia[index] = croppedImage;
});
}
Tùy chỉnh tỷ lệ cắt (Aspect Ratio)
Module hỗ trợ các tỷ lệ cắt ảnh sau:
enum CropAspectRatio {
original, // Giữ nguyên tỷ lệ gốc
square, // Vuông (1:1)
ratio3x2, // Tỷ lệ 3:2
ratio4x3, // Tỷ lệ 4:3
ratio5x3, // Tỷ lệ 5:3
ratio5x4, // Tỷ lệ 5:4
ratio7x5, // Tỷ lệ 7:5
ratio16x9, // Tỷ lệ 16:9
}
MediaOptions cho gallery
MediaOptions.gallery(
maxWidth: 1200,
maxHeight: 1200,
imageQuality: 85,
allowMultiple: true,
includeVideo: true,
cropOptions: cropOptions,
)
MediaOptions cho camera
MediaOptions.camera(
maxWidth: 1200,
maxHeight: 1200,
imageQuality: 90,
preferredCameraDevice: CameraDevice.front,
includeVideo: true,
maxDuration: const Duration(seconds: 30),
cropOptions: cropOptions,
)
Xử lý lỗi
try {
// Thực hiện các thao tác media
} on MediaPermissionException catch (e) {
// Xử lý lỗi quyền truy cập
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Cần cấp quyền'),
content: Text(e.message),
actions: [
TextButton(
onPressed: () => openAppSettings(),
child: const Text('Mở cài đặt'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Đóng'),
),
],
),
);
} on MediaOperationException catch (e) {
// Xử lý lỗi thao tác
showSnackBar(e.message);
} on MediaTypeException catch (e) {
// Xử lý lỗi định dạng
showSnackBar(e.message);
} catch (e) {
// Xử lý lỗi khác
showSnackBar('Đã xảy ra lỗi: $e');
}
Ứng dụng mẫu
Package này cung cấp một ứng dụng mẫu đầy đủ trong thư mục example. Bạn có thể xem và chạy để hiểu rõ hơn cách sử dụng package.
cd example
flutter run
API Reference
Classes
MediaController: Controller chính để thực hiện các thao tác mediaMediaItem: Đại diện cho một file media (ảnh hoặc video)MediaOptions: Cấu hình cho việc chọn mediaCropOptions: Cấu hình cho việc cắt ảnhMediaPickerButton: Widget button để chọn mediaMediaPreview: Widget hiển thị xem trước media
Enums
MediaType: Loại media (image, video)MediaSource: Nguồn media (gallery, camera)CropAspectRatio: Tỷ lệ khung hình cho cắt ảnh
Yêu cầu
- Flutter: >=1.17.0
- Dart: >=3.7.0
- Android: minSdkVersion 21 (Android 5.0)
- iOS: iOS 11.0 trở lên
Các package phụ thuộc
image_picker: ^1.1.2image_cropper: ^9.0.0path_provider: ^2.1.5permission_handler: ^11.4.0
Đóng góp
Mọi đóng góp đều được hoan nghênh! Nếu bạn phát hiện lỗi hoặc có ý tưởng cải thiện package, vui lòng tạo issue hoặc gửi pull request.
License
MIT License - xem file LICENSE để biết thêm chi tiết.