Flutter图片浏览插件photo_gallery的使用
Flutter图片浏览插件photo_gallery的使用
Photo Gallery
photo_gallery
是一个Flutter插件,可以从移动设备的本地相册中检索图片和视频。
安装
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>
使用
以下是photo_gallery
的一些基本用法:
-
列出相册中的专辑
final List<Album> imageAlbums = await PhotoGallery.listAlbums(); final List<Album> videoAlbums = await PhotoGallery.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(); // ... }
-
获取单个媒体文件
final Medium medium = await PhotoGallery.getMedium( mediumId: "10", mediumType: MediumType.image );
-
获取文件
final File file = await medium.getFile();
-
获取缩略图数据
final List<int> data = await medium.getThumbnail( width: 128, height: 128, highQuality: true, );
-
显示媒体缩略图
FadeInImage( fit: BoxFit.cover, placeholder: MemoryImage(kTransparentImage), image: ThumbnailProvider( mediumId: mediumId, mediumType: MediumType.image, width: 128, height: 128, hightQuality: true, ), )
-
显示完整尺寸的图片
FadeInImage( fit: BoxFit.cover, placeholder: MemoryImage(kTransparentImage), image: PhotoProvider( mediumId: mediumId, ), )
示例代码
这是一个完整的示例应用,展示了如何使用photo_gallery
插件来浏览相册、查看专辑内容以及展示媒体文件(包括图片和视频)。
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:photo_gallery/photo_gallery.dart';
import 'package:transparent_image/transparent_image.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(MyApp());
}
/// The main widget of example app
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Album>? _albums;
bool _loading = false;
@override
void initState() {
super.initState();
_loading = true;
initAsync();
}
Future<void> initAsync() async {
if (await _promptPermissionSetting()) {
List<Album> albums = await PhotoGallery.listAlbums();
setState(() {
_albums = albums;
_loading = false;
});
}
setState(() {
_loading = false;
});
}
Future<bool> _promptPermissionSetting() async {
if (Platform.isIOS) {
if (await Permission.photos.request().isGranted || await Permission.storage.request().isGranted) {
return true;
}
}
if (Platform.isAndroid) {
if (await Permission.storage.request().isGranted ||
await Permission.photos.request().isGranted && await Permission.videos.request().isGranted) {
return true;
}
}
return false;
}
@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,
),
),
),
],
),
),
),
],
),
);
},
),
),
);
}
}
/// The album page widget
class AlbumPage extends StatefulWidget {
/// Album object to show in the page
final Album album;
/// The constructor of AlbumPage
AlbumPage(Album album) : album = album;
@override
State<StatefulWidget> createState() => _AlbumPageState();
}
class _AlbumPageState extends State<AlbumPage> {
List<Medium>? _media;
@override
void initState() {
super.initState();
initAsync();
}
void initAsync() async {
MediaPage mediaPage = await widget.album.listMedia();
setState(() {
_media = mediaPage.items;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.of(context).pop(),
),
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,
),
),
),
),
),
],
),
),
);
}
}
/// The viewer page widget
class ViewerPage extends StatelessWidget {
/// The medium object to show in the page
final Medium medium;
/// The constructor of ViewerPage
ViewerPage(Medium medium) : medium = medium;
@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 {
PhotoGallery.deleteMedium(mediumId: medium.id);
},
child: FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: PhotoProvider(mediumId: medium.id),
),
)
: VideoProvider(
mediumId: medium.id,
),
),
),
);
}
}
/// The video provider widget
class VideoProvider extends StatefulWidget {
/// The identifier of medium
final String mediumId;
/// The constructor of VideoProvider
const VideoProvider({
required this.mediumId,
});
@override
_VideoProviderState createState() => _VideoProviderState();
}
class _VideoProviderState extends State<VideoProvider> {
VideoPlayerController? _controller;
File? _file;
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
initAsync();
});
super.initState();
}
Future<void> initAsync() async {
try {
_file = await PhotoGallery.getFile(mediumId: widget.mediumId);
_controller = VideoPlayerController.file(_file!);
_controller?.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
} catch (e) {
print("Failed : $e");
}
}
@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的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图片浏览插件photo_gallery的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用photo_gallery
插件来实现图片浏览功能的示例代码。photo_gallery
插件允许你展示一个图片画廊,并支持图片的滑动浏览。
首先,你需要在你的pubspec.yaml
文件中添加photo_gallery
依赖:
dependencies:
flutter:
sdk: flutter
photo_gallery: ^x.y.z # 请将x.y.z替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,你可以在你的Flutter项目中创建一个简单的画廊应用。以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:photo_gallery/photo_gallery.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Photo Gallery Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PhotoGalleryScreen(),
);
}
}
class PhotoGalleryScreen 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('Photo Gallery'),
),
body: Center(
child: PhotoGallery(
images: imageUrls.map((url) => NetworkImage(url)).toList(),
pageController: PageController(),
onPageChanged: (index) {
print('Current image index: $index');
},
),
),
);
}
}
class NetworkImage extends StatelessWidget {
final String url;
NetworkImage(this.url);
@override
Widget build(BuildContext context) {
return Image.network(
url,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded.toDouble() /
loadingProgress.expectedTotalBytes!.toDouble()
: null,
),
);
},
errorWidget: (context, error, stackTrace) {
return Icon(Icons.error);
},
);
}
}
在这个示例中:
MyApp
是应用程序的根widget,它定义了一个基本的Material应用,并设置了主题和主页。PhotoGalleryScreen
是主页widget,它包含了图片画廊。imageUrls
是一个包含图片URL的列表。PhotoGallery
widget用于显示图片画廊,并接受一个图片列表、一个PageController
以及一个页面改变时的回调函数。NetworkImage
是一个自定义widget,用于从网络加载图片,并处理加载进度和错误情况。
注意:
photo_gallery
插件的具体实现可能有所不同,请确保参考插件的官方文档和示例代码进行适配。- 示例中的
PhotoGallery
widget是假设的,因为photo_gallery
插件的具体API可能与此不同。在实际使用中,请查阅插件的最新版本和文档。 - 如果
photo_gallery
插件没有直接提供PhotoGallery
widget,你可能需要使用其他Flutter组件(如PageView
)来实现图片画廊功能。