Flutter图片浏览插件photo_gallery_flutter的使用

发布于 1周前 作者 sinazl 来自 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

1 回复

更多关于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。
回到顶部