Flutter图片选择增强插件image_picker_plus_nic的使用

Flutter 图片选择增强插件 image_picker_plus_nic 的使用

当您尝试添加一个包(如 image_picker)来从图库或相机中选择图片时,您可能会遇到许多问题:

  • 如果您的应用支持多主题,image_picker 将不会响应。
  • 如果您的应用支持多语言,image_picker 将不会响应。
  • 如果您的应用具有精美的设计和良好的用户体验,image_picker 将破坏这一切,因为 image_picker 具有传统的图库显示界面。

image_picker_plus_nic 中,我们解决了所有这些问题,并提供了许多其他功能,如:

  • 您可以自定义图库的显示界面。
  • 您可以选择并裁剪选中的图片,具有不同的宽高比。
  • 您可以显示照片和视频,并从中进行选择。
  • 您可以显示图库、相机和视频,用户可以从这些选项中进行选择。

安装

iOS

  • 相机插件可以编译为任何版本的 iOS,但其功能需要 iOS 10 或更高版本。如果编译为 iOS 9,请确保在使用任何相机插件功能之前,通过编程检查设备上运行的 iOS 版本。例如,您可以使用 <a href="https://pub.dev/packages/device_info_plus">device_info_plus</a> 插件来检查 iOS 版本。

ios/Runner/Info.plist 添加两行:

  • 一行带有键 Privacy - Camera Usage Description 和描述。
  • 另一行带有键 Privacy - Microphone Usage Description 和描述。

如果以文本形式编辑 Info.plist,请添加:

<key>NSCameraUsageDescription</key>
<string>your usage description here</string>
<key>NSMicrophoneUsageDescription</key>
<string>your usage description here</string>

Android

  • 在您的 android/app/build.gradle 文件中,将最低 Android SDK 版本更改为 21(或更高),并将编译 SDK 更改为 31(或更高)。
compileSdkVersion 33
minSdkVersion 21
  • 向您的 AndroidManifest.xml 添加此权限:
<manifest>
    ...
    <application
        android:requestLegacyExternalStorage="true"
    ...
    <uses-permission android:name="android.permission.INTERNET"/>
    </manifest>

1. 添加依赖

在您的包的 pubspec.yaml 文件中添加以下内容:

dependencies:
  image_picker_plus_nic: [last_version]

2. 安装

您可以从命令行安装包:

使用 pub

$ pub get image_picker_plus_nic

使用 Flutter

$ flutter pub add image_picker_plus_nic

3. 导入

在您的 Dart 代码中,您可以使用以下导入语句:

import 'package:image_picker_plus_nic/image_picker_plus_nic.dart';

示例代码

以下是完整的示例代码:

import 'dart:io';

import 'package:image_picker_plus_nic/image_picker_plus_nic.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom gallery display',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);
  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: SafeArea(
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              normal1(context),
              normal2(context),
              normal3(context),
              normal4(context),
            ]),
      ),
    );
  }

  ElevatedButton normal1(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        ImagePickerPlus picker = ImagePickerPlus(context);
        UiTexts uiTexts = const UiTexts(
            titleGallery: "相簿", titleCrop: "裁切", ok: "確定", cancel: "取消");
        SelectedImagesDetails? details =
            await picker.pickImage(source: ImageSource.camera, uiText: uiTexts, primaryColor: Color(0xff1fc97b), textStyle: TextStyle());
        if (details != null) await displayDetails(details);
      },
      child: const Text("开相机"),
    );
  }

  ElevatedButton normal2(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        ImagePickerPlus picker = ImagePickerPlus(context);
        UiTexts uiTexts = const UiTexts(
            titleGallery: "相簿", titleCrop: "裁切", ok: "確定", cancel: "取消");
        SelectedImagesDetails? details = await picker.pickImage(
            source: ImageSource.gallery, uiText: uiTexts, primaryColor: Color(0xff1fc97b), textStyle: TextStyle());
        if (details != null) await displayDetails(details);
      },
      child: const Text("从相簿单选照片"),
    );
  }

  ElevatedButton normal3(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        ImagePickerPlus picker = ImagePickerPlus(context);
        UiTexts uiTexts = const UiTexts(
            titleGallery: "相簿", titleCrop: "裁切", ok: "確定", cancel: "取消");
        SelectedImagesDetails? details = await picker.pickAndCropImage(
            source: ImageSource.gallery, uiText: uiTexts, selectIndex: 15, primaryColor: Color(0xff1fc97b), textStyle: TextStyle());
        if (details != null) await displayDetails(details);
      },
      child: const Text("裁切图片"),
    );
  }

  ElevatedButton normal4(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        ImagePickerPlus picker = ImagePickerPlus(context);
        UiTexts uiTexts = const UiTexts(
            titleGallery: "相簿",
            titleCrop: "裁切",
            ok: "確定",
            multiOk: '确认上传 (%d/%d)',
            cancel: "取消");
        final details = await picker.pickMultiImage(
            source: ImageSource.gallery, uiText: uiTexts, primaryColor: Color(0xff1FC97B), textStyle: TextStyle());
        if (details != null) await displayDetails(details);
      },
      child: const Text("相簿多选"),
    );
  }

  Future<void> displayDetails(SelectedImagesDetails details) async {
    await Navigator.of(context).push(
      CupertinoPageRoute(
        builder: (context) {
          return DisplayImages(
              selectedBytes: details.selectedFiles,
              details: details,
              aspectRatio: details.aspectRatio);
        },
      ),
    );
  }
}

class DisplayImages extends StatefulWidget {
  final List<SelectedByte> selectedBytes;
  final double aspectRatio;
  final SelectedImagesDetails details;
  const DisplayImages({
    Key? key,
    required this.details,
    required this.selectedBytes,
    required this.aspectRatio,
  }) : super(key: key);

  [@override](/user/override)
  State<DisplayImages> createState() => _DisplayImagesState();
}

class _DisplayImagesState extends State<DisplayImages> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Selected images/videos')),
      body: ListView.builder(
        itemBuilder: (context, index) {
          SelectedByte selectedByte = widget.selectedBytes[index];
          if (!selectedByte.isThatImage) {
            return _DisplayVideo(selectedByte: selectedByte);
          } else {
            return SizedBox(
              width: double.infinity,
              child: Image.file(selectedByte.selectedFile),
            );
          }
        },
        itemCount: widget.selectedBytes.length,
      ),
    );
  }
}

class _DisplayVideo extends StatefulWidget {
  final SelectedByte selectedByte;
  const _DisplayVideo({Key? key, required this.selectedByte}) : super(key: key);

  [@override](/user/override)
  State<_DisplayVideo> createState() => _DisplayVideoState();
}

class _DisplayVideoState extends State<_DisplayVideo> {
  late VideoPlayerController controller;
  late Future<void> initializeVideoPlayerFuture;

  [@override](/user/override)
  void initState() {
    super.initState();
    File file = widget.selectedByte.selectedFile;
    controller = VideoPlayerController.file(file);
    initializeVideoPlayerFuture = controller.initialize();
    controller.setLooping(true);
  }

  [@override](/user/override)
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: initializeVideoPlayerFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return Stack(
            alignment: Alignment.center,
            children: [
              AspectRatio(
                aspectRatio: controller.value.aspectRatio,
                child: VideoPlayer(controller),
              ),
              Align(
                alignment: Alignment.center,
                child: GestureDetector(
                  onTap: () {
                    setState(() {
                      if (controller.value.isPlaying) {
                        controller.pause();
                      } else {
                        controller.play();
                      }
                    });
                  },
                  child: Icon(
                    controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
                    color: Colors.white,
                    size: 45,
                  ),
                ),
              )
            ],
          );
        } else {
          return const Center(
            child: CircularProgressIndicator(strokeWidth: 1),
          );
        }
      },
    );
  }
}

更多关于Flutter图片选择增强插件image_picker_plus_nic的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图片选择增强插件image_picker_plus_nic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


image_picker_plus_nic 是一个基于 image_picker 的 Flutter 插件,它提供了更多功能来增强图片选择体验。以下是如何使用 image_picker_plus_nic 插件的详细步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 image_picker_plus_nic 的依赖。

dependencies:
  flutter:
    sdk: flutter
  image_picker_plus_nic: ^0.0.1  # 请确保使用最新版本

然后,运行 flutter pub get 来获取依赖。

2. 导入包

在你的 Dart 文件中导入 image_picker_plus_nic 包。

import 'package:image_picker_plus_nic/image_picker_plus_nic.dart';

3. 使用 ImagePickerPlusNic 选择图片

ImagePickerPlusNic 提供了多种方法来选择图片,包括从相册中选择、拍摄照片等。

选择单张图片

Future<void> pickImage() async {
  final ImagePickerPlusNic picker = ImagePickerPlusNic();
  final XFile? image = await picker.pickImage(source: ImageSource.gallery);

  if (image != null) {
    // 使用选中的图片
    print('图片路径: ${image.path}');
  } else {
    // 用户取消选择
    print('未选择图片');
  }
}

选择多张图片

Future<void> pickMultipleImages() async {
  final ImagePickerPlusNic picker = ImagePickerPlusNic();
  final List<XFile>? images = await picker.pickMultiImage();

  if (images != null && images.isNotEmpty) {
    // 使用选中的多张图片
    for (var image in images) {
      print('图片路径: ${image.path}');
    }
  } else {
    // 用户取消选择
    print('未选择图片');
  }
}

拍摄照片

Future<void> takePicture() async {
  final ImagePickerPlusNic picker = ImagePickerPlusNic();
  final XFile? image = await picker.pickImage(source: ImageSource.camera);

  if (image != null) {
    // 使用拍摄的照片
    print('图片路径: ${image.path}');
  } else {
    // 用户取消拍摄
    print('未拍摄照片');
  }
}

4. 处理权限

在 Android 和 iOS 上,使用相机和访问相册需要相应的权限。确保在 AndroidManifest.xmlInfo.plist 中添加必要的权限。

Android

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"/>

iOS

Info.plist 中添加以下键值对:

<key>NSCameraUsageDescription</key>
<string>我们需要访问您的相机以拍摄照片。</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>我们需要访问您的相册以选择照片。</string>

5. 处理图片

选择的图片通常以 XFile 对象返回。你可以将其转换为 File 对象,或者直接使用其路径来进行进一步处理。

import 'dart:io';

Future<void> useImage(File imageFile) async {
  // 你可以在这里处理图片
  print('图片文件: ${imageFile.path}');
}
回到顶部