Flutter图片浏览插件photo_gallery_flutter的使用
Flutter图片浏览插件photo_gallery_flutter的使用
photo_gallery_flutter
是一个用于从移动设备的本地相册中检索图片和视频的Flutter插件。本文将介绍如何安装和使用这个插件,并提供一个完整的示例demo。
安装
首先,在你的 pubspec.yaml
文件中添加 photo_gallery_flutter
作为依赖项:
dependencies:
photo_gallery_flutter: ^latest_version
iOS配置
在 <project root>/ios/Runner/Info.plist
文件中添加以下键值对:
<key>NSPhotoLibraryUsageDescription</key>
<string>Example usage description</string>
Android配置
在 <project root>/android/app/src/main/AndroidManifest.xml
文件中添加以下权限:
<manifest ...>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
</manifest>
使用方法
列出相册
你可以列出图片或视频相册:
final List<Album> imageAlbums = await PhotoGalleryFlutter.listAlbums();
final List<Album> videoAlbums = await PhotoGalleryFlutter.listAlbums(
mediumType: MediumType.video,
newest: false,
hideIfEmpty: false,
);
列出相册中的媒体
获取某个相册中的媒体:
final MediaPage imagePage = await imageAlbum.listMedia();
final MediaPage videoPage = await imageAlbum.listMedia(
skip: 5,
take: 10,
);
final List<Medium> allMedia = [
...imagePage.items,
...videoPage.items,
];
加载更多媒体
如果当前页面不是最后一页,可以加载更多媒体:
if (!imagePage.isLast) {
final nextImagePage = await imagePage.nextPage();
// ...
}
获取单个媒体
获取特定ID的媒体:
final Medium medium = await PhotoGalleryFlutter.getMedium(
mediumId: "10",
mediumType: MediumType.image
);
获取文件
获取媒体文件:
final File file = await medium.getFile();
final File file = await PhotoGalleryFlutter.getFile(mediumId: mediumId);
获取缩略图数据
获取媒体缩略图数据:
final List<int> data = await medium.getThumbnail();
final List<int> data = await PhotoGalleryFlutter.getThumbnail(mediumId: mediumId);
// 指定宽度、高度和高质量选项(仅适用于iOS和Android API 29+)
final List<int> data = await medium.getThumbnail(
width: 128,
height: 128,
highQuality: true,
);
final List<int> data = await PhotoGalleryFlutter.getThumbnail(
mediumId: mediumId,
mediumType: MediumType.image,
width: 128,
height: 128,
highQuality: true,
);
显示媒体缩略图
使用 ThumbnailProvider
显示缩略图:
FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: ThumbnailProvider(
mediumId: mediumId,
mediumType: MediumType.image,
width: 128,
height: 128,
highQuality: true,
),
)
显示完整尺寸图片
使用 PhotoProvider
显示完整尺寸的图片:
FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: PhotoProvider(mediumId: mediumId),
)
示例Demo
下面是一个完整的示例代码,展示了如何使用 photo_gallery_flutter
插件来展示相册和媒体:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:photo_gallery_flutter/photo_gallery_flutter.dart';
import 'package:transparent_image/transparent_image.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Album>? _albums;
bool _loading = false;
[@override](/user/override)
void initState() {
super.initState();
_loading = true;
initAsync();
}
Future<void> initAsync() async {
if (await _promptPermissionSetting()) {
List<Album> albums = await PhotoGalleryFlutter.listAlbums();
setState(() {
_albums = albums;
_loading = false;
});
}
setState(() {
_loading = false;
});
}
Future<bool> _promptPermissionSetting() async {
if (Platform.isIOS) {
return await Permission.photos.request().isGranted ||
await Permission.storage.request().isGranted;
}
if (Platform.isAndroid) {
return await Permission.storage.request().isGranted ||
await Permission.photos.request().isGranted &&
await Permission.videos.request().isGranted;
}
return false;
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Photo gallery example'),
),
body: _loading
? Center(child: CircularProgressIndicator())
: LayoutBuilder(
builder: (context, constraints) {
double gridWidth = (constraints.maxWidth - 20) / 3;
double gridHeight = gridWidth + 33;
double ratio = gridWidth / gridHeight;
return Container(
padding: EdgeInsets.all(5),
child: GridView.count(
childAspectRatio: ratio,
crossAxisCount: 3,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
children: <Widget>[
...?_albums?.map(
(album) => GestureDetector(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (context) => AlbumPage(album)),
),
child: Column(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Container(
color: Colors.grey[300],
height: gridWidth,
width: gridWidth,
child: FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: AlbumThumbnailProvider(
album: album,
highQuality: true,
),
),
),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 2.0),
child: Text(
album.name ?? "Unnamed Album",
maxLines: 1,
textAlign: TextAlign.start,
style: TextStyle(height: 1.2, fontSize: 16),
),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 2.0),
child: Text(
album.count.toString(),
textAlign: TextAlign.start,
style: TextStyle(height: 1.2, fontSize: 12),
),
),
],
),
),
),
],
),
);
},
),
),
);
}
}
class AlbumPage extends StatefulWidget {
final Album album;
AlbumPage(this.album);
[@override](/user/override)
State<StatefulWidget> createState() => _AlbumPageState();
}
class _AlbumPageState extends State<AlbumPage> {
List<Medium>? _media;
[@override](/user/override)
void initState() {
super.initState();
initAsync();
}
void initAsync() async {
MediaPage mediaPage = await widget.album.listMedia();
setState(() {
_media = mediaPage.items;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(icon: Icon(Icons.arrow_back_ios), onPressed: () => Navigator.of(context).pop()),
actions: [
IconButton(
icon: Icon(Icons.delete),
onPressed: () async {
List<MediumToDelete> mediaToDelete = _media!
.map((e) => MediumToDelete(e.id, e.mediumType))
.toList();
await PhotoGalleryFlutter.deleteMedium(mediumToDelete: mediaToDelete);
},
),
],
title: Text(widget.album.name ?? "Unnamed Album"),
),
body: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0,
children: <Widget>[
...?_media?.map(
(medium) => GestureDetector(
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => ViewerPage(medium))),
child: Container(
color: Colors.grey[300],
child: FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: ThumbnailProvider(
mediumId: medium.id,
mediumType: medium.mediumType,
highQuality: true,
),
),
),
),
),
],
),
),
);
}
}
class ViewerPage extends StatelessWidget {
final Medium medium;
ViewerPage(this.medium);
[@override](/user/override)
Widget build(BuildContext context) {
DateTime? date = medium.creationDate ?? medium.modifiedDate;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(onPressed: () => Navigator.of(context).pop(), icon: Icon(Icons.arrow_back_ios)),
title: date != null ? Text(date.toLocal().toString()) : null,
),
body: Container(
alignment: Alignment.center,
child: medium.mediumType == MediumType.image
? GestureDetector(
onTap: () async {
await PhotoGalleryFlutter.deleteMedium(mediumToDelete: [MediumToDelete(medium.id, medium.mediumType)]);
},
child: FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: PhotoProvider(mediumId: medium.id),
),
)
: VideoProvider(mediumId: medium.id),
),
),
);
}
}
class VideoProvider extends StatefulWidget {
final String mediumId;
const VideoProvider({required this.mediumId});
[@override](/user/override)
_VideoProviderState createState() => _VideoProviderState();
}
class _VideoProviderState extends State<VideoProvider> {
VideoPlayerController? _controller;
File? _file;
[@override](/user/override)
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
initAsync();
});
super.initState();
}
Future<void> initAsync() async {
try {
_file = await PhotoGalleryFlutter.getFile(mediumId: widget.mediumId);
_controller = VideoPlayerController.file(_file!);
_controller?.initialize().then((_) {
setState(() {});
});
} catch (e) {
print("Failed : $e");
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return _controller == null || !_controller!.value.isInitialized
? Container()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AspectRatio(aspectRatio: _controller!.value.aspectRatio, child: VideoPlayer(_controller!)),
TextButton(
onPressed: () {
setState(() {
_controller!.value.isPlaying ? _controller!.pause() : _controller!.play();
});
},
child: Icon(_controller!.value.isPlaying ? Icons.pause : Icons.play_arrow),
),
],
);
}
}
更多关于Flutter图片浏览插件photo_gallery_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图片浏览插件photo_gallery_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用photo_gallery_flutter
插件的示例代码。请注意,photo_gallery_flutter
可能不是一个真实存在的Flutter插件(在撰写此回答时,我未能在pub.dev上找到此插件),但我会基于一个假设的图片浏览插件的功能来提供一个示例。通常,图片浏览插件会提供展示图片、滑动浏览等功能。
假设有一个名为image_gallery_flutter
的插件(因为photo_gallery_flutter
可能不存在,这里用image_gallery_flutter
作为替代),以下是其使用示例:
1. 添加依赖
首先,在pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
image_gallery_flutter: ^x.y.z # 假设的版本号
然后运行flutter pub get
来安装依赖。
2. 导入插件
在你的Dart文件中导入插件:
import 'package:flutter/material.dart';
import 'package:image_gallery_flutter/image_gallery_flutter.dart';
3. 使用插件
下面是一个简单的示例,展示如何使用这个假设的图片浏览插件来展示一组图片:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Gallery Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ImageGalleryScreen(),
);
}
}
class ImageGalleryScreen extends StatelessWidget {
final List<String> imageUrls = [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
'https://example.com/image3.jpg',
// 添加更多图片URL
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Gallery'),
),
body: Center(
child: ImageGallery(
images: imageUrls.map((url) => NetworkImage(url)).toList(),
onPageChanged: (int index) {
print('Current page index: $index');
},
),
),
);
}
}
// 假设ImageGallery是image_gallery_flutter插件提供的一个Widget
class ImageGallery extends StatefulWidget {
final List<ImageProvider> images;
final ValueChanged<int> onPageChanged;
ImageGallery({required this.images, required this.onPageChanged});
@override
_ImageGalleryState createState() => _ImageGalleryState();
}
class _ImageGalleryState extends State<ImageGallery> {
late final PageController _pageController;
@override
void initState() {
super.initState();
_pageController = PageController();
_pageController.addListener(() {
final int page = _pageController.page!.round();
if (page != widget.images.indexOf(_currentPageImage.key.value)) {
widget.onPageChanged(page);
setState(() {
// 这里实际上不需要重新构建整个列表,只是为了示例
// 在真实场景中,你可能只需要更新当前显示的图片
});
}
});
}
late final ValueKey<int> _currentPageImage;
@override
void didUpdateWidget(covariant ImageGallery oldWidget) {
super.didUpdateWidget(oldWidget);
// 更新当前页面图片的关键帧,以便在图片更改时触发重建
_currentPageImage = ValueKey(_pageController.page!.round());
}
@override
Widget build(BuildContext context) {
return PageView.builder(
controller: _pageController,
itemCount: widget.images.length,
itemBuilder: (context, index) {
return Image.network(
// 这里假设每个ImageProvider都是NetworkImage,实际情况可能不同
(widget.images[index] as NetworkImage).url,
key: _currentPageImage, // 使用关键帧确保在滑动时正确重建图片
);
},
);
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
}
注意:
- 上面的代码假设
ImageGallery
是一个由插件提供的Widget,但实际上,Flutter中并没有一个名为ImageGallery
的标准Widget。因此,上面的ImageGallery
类是一个假设的实现,用于展示如何使用PageView来实现图片浏览功能。 - 在真实场景中,你应该查阅插件的官方文档来了解如何正确使用它。
- 由于
photo_gallery_flutter
可能不存在,我使用了image_gallery_flutter
作为替代名称。如果确实存在一个名为photo_gallery_flutter
的插件,请查阅其官方文档以获取正确的使用方法和API。