- vừa được xem lúc

Tương tác với Camera và Thư viện ảnh (Gallery) trong Flutter

0 0 1

Người đăng: Coder Tập Sự

Theo Viblo Asia

Chào mọi người lại là mình Coder tập sự đây, sau thời gian bận chút việc cá nhân thì hôm nay mình và các bạn lại tiếp tục cùng nhau tìm hiểu flutter từ con số 0 nhé.

Khi phát triển ứng dụng di động, việc cho phép người dùng chụp ảnh hoặc chọn ảnh/video từ thư viện là một tính năng cực kỳ phổ biến và quan trọng. Từ ứng dụng mạng xã hội, ứng dụng ghi chú có hình ảnh, đến các ứng dụng mua sắm yêu cầu tải ảnh sản phẩm, khả năng tương tác với camera và gallery của thiết bị là không thể thiếu.

Trong Flutter, chúng ta sẽ thực hiện điều này một cách dễ dàng nhờ vào một package mạnh mẽ và được cộng đồng tin dùng.

Package image_picker

Để tương tác với camera và thư viện ảnh, chúng ta sẽ sử dụng package image_picker. Đây là package chính thức và được duy trì tốt, cung cấp một API đơn giản để truy cập các tính năng này trên cả Android và iOS.

Cài đặt image_picker:

Đầu tiên, hãy thêm dependency sau vào file pubspec.yaml của dự án chúng ta:

dependencies: flutter: sdk: flutter image_picker: ^1.1.0

Sau đó, chạy flutter pub get trong terminal để tải package.

Cấu hình Native (Quan trọng ⚠️):

Để image_picker hoạt động đúng, chúng ta cần thêm một số cấu hình liên quan đến quyền truy cập vào file AndroidManifest.xml (Android) và Info.plist (iOS).

Cho Android:

Mở file android/app/src/main/AndroidManifest.xml và đảm bảo rằng bạn có các quyền sau bên trong thẻ <manifest> :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.CAMERA"/> <application ...> ... </application>
</manifest>

Lưu ý cho Android 13 (API 33) trở lên: Với Android 13 trở lên, quyền READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE đã được thay thế bằng các quyền truy cập cụ thể hơn vào loại media. Nếu chúng ta đang nhắm mục tiêu SDK 33+, thì nên thay thế chúng bằng:

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

Nếu chúng ta vẫn muốn hỗ trợ các phiên bản Android cũ hơn, hãy giữ cả hai bộ quyền.

Cho iOS:

Mở file ios/Runner/Info.plist và thêm các khóa sau vào trong thẻ <dict>:

<dict> ... <key>NSPhotoLibraryUsageDescription</key> <string>Ứng dụng cần truy cập thư viện ảnh để cho phép bạn chọn ảnh.</string> <key>NSCameraUsageDescription</key> <string>Ứng dụng cần truy cập camera để chụp ảnh.</string> <key>NSMicrophoneUsageDescription</key> <string>Ứng dụng cần truy cập microphone để quay video.</string> ...
</dict>

Đây là các chuỗi mô tả lý do ứng dụng của chúng ta cần các quyền này, và sẽ được hiển thị cho người dùng khi ứng dụng yêu cầu cấp quyền lần đầu.

Chụp ảnh/Chọn ảnh/video từ Camera và Gallery

Sau khi đã cài đặt và cấu hình, việc sử dụng image_picker rất đơn giản:

Bước 1: Import thư viện

import 'package:image_picker/image_picker.dart';

Bước 2: Tạo instance của ImagePicker

final ImagePicker _picker = ImagePicker();

Bước 3: Thực hiện thao tác chọn/chụp

  • Chọn ảnh từ Gallery:
Future<void> _pickImageFromGallery() async { final XFile? image = await _picker.pickImage(source: ImageSource.gallery); if (image != null) { // Xử lý ảnh đã chọn: hiển thị, upload, v.v. print('Đường dẫn ảnh từ Gallery: ${image.path}'); // Ví dụ: setState(() { _imageFile = File(image.path); }); }
}
  • Chụp ảnh bằng Camera:
Future<void> _captureImageFromCamera() async { final XFile? image = await _picker.pickImage(source: ImageSource.camera); if (image != null) { // Xử lý ảnh đã chụp print('Đường dẫn ảnh từ Camera: ${image.path}'); // Ví dụ: setState(() { _imageFile = File(image.path); }); }
}
  • Chọn video từ Gallery:
Future<void> _pickVideoFromGallery() async { final XFile? video = await _picker.pickVideo(source: ImageSource.gallery); if (video != null) { // Xử lý video đã chọn print('Đường dẫn video từ Gallery: ${video.path}'); }
}

Bước 4: Xử lý và hiển thị file media

picker.pickImage()picker.pickVideo() đều trả về một đối tượng XFile (cross-platform file). XFile có thuộc tính path chứa đường dẫn đến file media đã chọn hoặc chụp. Chúng ta có thể dùng đường dẫn này để hiển thị ảnh bằng Image.file() hoặc video bằng các package video player.

Tuyệt vời! Để bạn có thể chạy thử và thấy ngay kết quả, đây là ví dụ đầy đủ của một ứng dụng Flutter sử dụng image_picker để chụp ảnh hoặc chọn ảnh từ thư viện và hiển thị chúng. Đảm bảo bạn đã thêm image_picker: ^1.1.0 (hoặc phiên bản mới nhất) vào pubspec.yaml và chạy flutter pub get. Đồng thời, đừng quên cấu hình quyền truy cập cho Android và iOS như đã hướng dẫn ở bài viết trước nhé! Dart import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; void main() { runApp(const MyApp());
} class MyApp extends StatelessWidget { const MyApp({super.key});  Widget build(BuildContext context) { return const MaterialApp( home: ImagePickerDemo(), debugShowCheckedModeBanner: false, ); }
} class ImagePickerDemo extends StatefulWidget { const ImagePickerDemo({super.key});  State<ImagePickerDemo> createState() => _ImagePickerDemoState();
} class _ImagePickerDemoState extends State<ImagePickerDemo> { File? _selectedImage; final ImagePicker _picker = ImagePicker(); // Phương thức để chọn ảnh từ Gallery Future<void> _pickImageFromGallery() async { // Gọi pickImage với source là ImageSource.gallery final XFile? image = await _picker.pickImage(source: ImageSource.gallery); if (image != null) { setState(() { _selectedImage = File(image.path); }); // Hiển thị thông báo hoặc thực hiện hành động khác với ảnh đã chọn ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Đã chọn ảnh từ Gallery: ${image.path.split('/').last}')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Chưa chọn ảnh nào từ Gallery')), ); } } // Phương thức để chụp ảnh bằng Camera Future<void> _captureImageFromCamera() async { final XFile? image = await _picker.pickImage(source: ImageSource.camera); if (image != null) { setState(() { _selectedImage = File(image.path); }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Đã chụp ảnh từ Camera: ${image.path.split('/').last}')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Chưa chụp ảnh nào bằng Camera')), ); } } void _clearImage() { setState(() { _selectedImage = null; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Đã xóa ảnh hiện tại')), ); }  Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Image Picker Demo'), centerTitle: true, backgroundColor: Colors.blueAccent, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Container( width: 300, height: 200, decoration: BoxDecoration( border: Border.all(color: Colors.grey, width: 1.0), borderRadius: BorderRadius.circular(8.0), ), child: _selectedImage == null ? const Center( child: Text( 'Chưa có ảnh nào được chọn.', style: TextStyle(color: Colors.grey), ), ) : ClipRRect( borderRadius: BorderRadius.circular(8.0), child: Image.file( _selectedImage!, fit: BoxFit.cover, ), ), ), const SizedBox(height: 30), ElevatedButton.icon( onPressed: _pickImageFromGallery, icon: const Icon(Icons.photo_library), label: const Text('Chọn ảnh từ Gallery'), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15), textStyle: const TextStyle(fontSize: 16), ), ), const SizedBox(height: 15), ElevatedButton.icon( onPressed: _captureImageFromCamera, icon: const Icon(Icons.camera_alt), label: const Text('Chụp ảnh bằng Camera'), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15), textStyle: const TextStyle(fontSize: 16), ), ), const SizedBox(height: 15), if (_selectedImage != null) ElevatedButton.icon( onPressed: _clearImage, icon: const Icon(Icons.clear), label: const Text('Xóa ảnh'), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15), textStyle: const TextStyle(fontSize: 16), ), ), ], ), ), ); }
}

Kết luận

Package image_picker là một công cụ mạnh mẽ và dễ sử dụng để tương tác với camera và thư viện ảnh trên thiết bị. Bằng cách làm theo các bước cài đặt, cấu hình quyền và sử dụng API đơn giản, chúng ta có thể dễ dàng thêm khả năng chụp ảnh hoặc chọn file media vào ứng dụng Flutter của mình.

Đây là một bước quan trọng trong việc xây dựng các ứng dụng di động thực tế. Hãy thực hành với ví dụ trên để nắm vững cách hoạt động của image_picker nhé!

Tham khảo

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 1: Làm quen cô nàng Flutter

Lời mở đầu. Gần đây, Flutter nổi lên và được Google PR như một xu thế của lập trình di động vậy.

0 0 301

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 3: Lột trần cô nàng Flutter, BuildContext là gì?

Lời mở đầu. Màn làm quen cô nàng FLutter ở Phần 1 đã gieo rắc vào đầu chúng ta quá nhiều điều bí ẩn về nàng Flutter.

1 1 362

- vừa được xem lúc

Flutter Animation: Creating medium’s clap animation in flutte Part II

Trong phần 1 mình đã giới thiệu với các bạn cơ bản về Animation trong Flutter. Score Widget Size Animation.

0 0 72

- vừa được xem lúc

Flutter - GetX - Using GetConnect to handle API request (Part 4)

Giới thiệu. Xin chào các bạn, lại là mình với series về GetX và Flutter.

0 0 371

- vừa được xem lúc

StatefulWidget và StatelessWidget trong Flutter

I. Mở đầu. Khi các bạn build một ứng dụng với Flutter thì Widgets là thứ không thể thiếu đúng không ạ. Và 2 loại Widget không thể thiếu đó là StatefullWidget và StatelessWidget.

0 0 158

- vừa được xem lúc

Tìm hiểu về Riverpod - Provider nhưng không hắn :v

Trong Flutter có rất nhiều các quản lý state: Provider, Bloc, GetX, Redux,... khó mà nói cái nào tốt hơn cái nào. Tuy nhiên nếu bạn đã làm quen với Provider thì không ngại để tìm hiểu thêm về Riverpod. Một bản nâng cấp của Provider. Nếu bạn để ý thì cái tên "Riverpod" là các chữ cái của "Provider" đ

0 0 73