小工具知识网

当前位置: 首页 > 行业知识 > flutter实现选择图片视频上传到oss和图片视频的预览功能

行业知识

flutter实现选择图片视频上传到oss和图片视频的预览功能

2026-11-09 13:16:52 来源:互联网转载

一、效果图

flutter实现选择图片视频上传到oss和图片视频的预览功

二、所需要的依赖

image_picker: ^1.1.0 //选择图片

flutter_oss_aliyun: ^6.4.1 //图片上传到阿里云oss

uuid: ^4.4.0 //生成唯一uuid

interactiveviewer_gallery: ^0.6.0 //图片视频预览

cached_network_image: ^3.3.1 //缓存网络图片,避免多次请求

video_thumbnail: ^0.5.3 //视频生成缩略图

video_player: ^2.8.6 //视频播放

三、主要源码解析

1、初始化oss,参考 flutter_oss_aliyun库

initUploadOss() {  Auth authGetter() {    return Auth(      accessKey: "",      accessSecret: '',      expire: '2024-05-23T13:26:58Z',      secureToken:'',    );  }  Client.init(      ossEndpoint: ProjectConfig.ossEndpoint,      bucketName: ProjectConfig.bucketName,      authGetter: authGetter);}

2、选择上传图片视频方式

List selectPictureMethodDicData = [  {    "label": "选择照片",    "value": "0",  },  {    "label": "拍照",    "value": "1",  },  {    "label": "选择视频",    "value": "2",  },  {    "label": "拍视频",    "value": "3",  },   {    "label": "选择单张照片/视频",    "value": "4",  },  {    "label": "选择多张照片或者视频",    "value": "5",  },];

3、定义MedaiModel类

import 'dart:typed_data';class MedaiModel {  int process;  String ossUrl;  final String localUrl;  final Uint8List bytes;  final String extension;  final String id;  final String thumbnailPath;  final String sourceType;  MedaiModel({    required this.process,    required this.ossUrl,    required this.localUrl,    required this.bytes,    required this.extension,    required this.id,    required this.thumbnailPath,    required this.sourceType,  });  factory MedaiModel.fromJson(Map json) {    return MedaiModel(      process: json["process"] ?? 0,      ossUrl: json["ossUrl"] ?? "",      localUrl: json["localUrl"] ?? "",      bytes: json["bytes"] ?? Uint8List(0),      extension: json["extension"] ?? "",      id: json["id"] ?? "",      thumbnailPath: json["thumbnailPath"] ?? "",      sourceType: json["sourceType"] ?? "",    );  }  Map toJson() {    return {      'process': process,      'ossUrl': ossUrl,      'localUrl': localUrl,      'bytes': bytes,      'extension': extension,      'id': id,      'thumbnailPath': thumbnailPath,      'sourceType': sourceType,    };  }}

4、根据选择视频方式产品图片视频资源

Future selectMedia(String value, RxList? filesController,    {bool isMultiple = false,    int fileSize = 0,    int limit = 1,    int imageQuality = 90,    Duration? maxDuration,    bool isMedia = false}) async {  final ImagePicker picker = ImagePicker();  ImageSource imageSource = ImageSource.gallery;  List? files = [];  if (value == "0" || value == "2") {    //相册    imageSource = ImageSource.gallery;  } else if (value == "1" || value == "3") {    //相机    imageSource = ImageSource.camera;  }  if (value == "0" || value == "1") {    //照片    if (isMultiple) {      final List images =          await picker.pickMultiImage(imageQuality: imageQuality, limit: limit);      files.addAll(images);    } else {      final XFile? image = await picker.pickImage(          source: imageSource, imageQuality: imageQuality);      if (image != null) {        files.add(image);      }    }  } else if (value == "2" || value == "3") {    //视频    final XFile? image =        await picker.pickVideo(source: imageSource, maxDuration: maxDuration);    if (image != null) {      files.add(image);    }  }  if (value == "4") {    final XFile? media = await picker.pickMedia(imageQuality: imageQuality);    if (media != null) {      files.add(media);    }  } else if (value == "5") {    final List medias = await picker.pickMultipleMedia(        imageQuality: imageQuality, limit: limit);    if (medias.length > 1) {      files.addAll(medias);    }  }  for (var file in files) {    bool isUpload = true;    Uint8List? bytes = await file.readAsBytes();    if (fileSize > 0) {      int? byte = bytes.lengthInBytes;      if (byte / 1024 / 1024 > fileSize) {        EasyLoading.showToast("资源大小应小于${fileSize}M");        isUpload = false;      }    }    if (isUpload) {      int indexOf = file.path.lastIndexOf(".");      String extension = file.path.substring(indexOf + 1);      String sourceType = getSourceType(file.path);      String thumbnailPath = file.path;      if (sourceType == 'video') {        thumbnailPath = await getVideoThumbnail(file.path);      }      MedaiModel medaiModel = MedaiModel.fromJson({        "uploadProcess": 0,        "ossUrl": "",        "localUrl": file.path,        "bytes": bytes,        "extension": extension,        "id": Uuid().v1(),        "thumbnailPath": thumbnailPath,        "sourceType": sourceType,      });      filesController!.add(medaiModel);    }  }  for (int i = 0; i  

5、判断资源类型

String getSourceType(String path) {  String ossPath = path.split("?")[0];  int index = ossPath.lastIndexOf(".");  String typeStr = ossPath.substring(index + 1).toUpperCase();  List imagesList = ["BMP", "JPG", "JPEG", "PNG", "GIF"];  List videoList = ["AVI", "WMV", "MPG", "MPEG", "MOV", "MP4"];  if (imagesList.contains(typeStr)) {    return "image";  } else if (videoList.contains(typeStr)) {    return "video";  } else {    return "image";  }}

6、获取视频缩略图

Future getVideoThumbnail(String path) async {  String? thumbnailPath = await VideoThumbnail.thumbnailFile(      video: path, imageFormat: ImageFormat.JPEG, maxWidth: 128, quality: 25);  return thumbnailPath!;}

7、获取资源显示的视图

Widget getSourceView(MedaiModel source,    {double width = 100, double height = 100}) {  if (source.sourceType == 'video') {    return Image.file(File(source.thumbnailPath),        width: width, height: height, fit: BoxFit.cover);  } else {    if (source.localUrl != '') {      return Image.file(File(source.localUrl),          width: width, height: height, fit: BoxFit.cover);    } else {      return CachedNetworkImage(          imageUrl: source.ossUrl,          width: width,          height: height,          fit: BoxFit.cover);    }  }}

8、打开预览图片

void openGallery(List sourceList, MedaiModel source) {  int initIndex = 0;  for (int i = 0; i  DisplayGesture(        child: InteractiveviewerGallery(          sources: sourceList,          initIndex: initIndex,          itemBuilder: (BuildContext context, int index, bool isFocus) {            MedaiModel sourceEntity = sourceList[index];            if (sourceEntity.sourceType == 'video') {              return PreviewVideo(                sourceEntity,                isFocus: isFocus,              );            } else {              return PreviewImage(sourceEntity);            }          },          onPageChanged: (int pageIndex) {            print("nell-pageIndex:$pageIndex");          },        ),      ),    ),  );}

9、预览图片视图

import 'dart:io';import 'package:cached_network_image/cached_network_image.dart';import 'package:company_manage_flutter/model/mediaModel.dart';import 'package:flutter/material.dart';class PreviewImage extends StatefulWidget {  MedaiModel  source;  PreviewImage(this.source);  @override  State createState() => _PreviewImageState();}class _PreviewImageState extends State {  @override  Widget build(BuildContext context) {    return GestureDetector(      behavior: HitTestBehavior.opaque,      onTap: () => Navigator.of(context).pop(),      child: Center(        child: Hero(          tag: widget.source.id,          child: widget.source.localUrl == ''              ? CachedNetworkImage(                  imageUrl: widget.source.ossUrl,                  fit: BoxFit.contain,                )              : Image.file(                  File(widget.source.localUrl),                  fit: BoxFit.contain,                ),        ),      ),    );  }}

10、预览视频视图

import 'dart:io';import 'package:company_manage_flutter/model/mediaModel.dart';import 'package:flutter/cupertino.dart';import 'package:flutter/material.dart';import 'package:video_player/video_player.dart';class PreviewVideo extends StatefulWidget {  final MedaiModel source;  final bool? isFocus;  PreviewVideo(this.source, {this.isFocus});  @override  State createState() => _PreviewVideoState();}class _PreviewVideoState extends State {  VideoPlayerController? _controller;  late VoidCallback listener;  _PreviewVideoState() {    listener = () {      if (!mounted) {        return;      }      setState(() {});    };  }  @override  void initState() {    super.initState();    init();  }  init() async {    if (widget.source.localUrl == '') {      _controller =          VideoPlayerController.networkUrl(Uri.parse(widget.source.ossUrl));    } else {      _controller =          VideoPlayerController.file(File(widget.source.localUrl));    }    // loop play  //  _controller!.setLooping(true);    await _controller!.initialize();    setState(() {});    _controller!.addListener(listener);  }  @override  void dispose() {    super.dispose();    _controller!.removeListener(listener);    _controller?.pause();    _controller?.dispose();  }  @override  void didUpdateWidget(covariant PreviewVideo oldWidget) {    super.didUpdateWidget(oldWidget);    if (oldWidget.isFocus! && !widget.isFocus!) {      // pause      _controller?.pause();    }  }  @override  Widget build(BuildContext context) {    return _controller!.value.isInitialized        ? Stack(            alignment: Alignment.center,            children: [              GestureDetector(                onTap: () {                  setState(() {                    _controller!.value.isPlaying                        ? _controller!.pause()                        : _controller!.play();                  });                },                child: Hero(                  tag: widget.source.id,                  child: AspectRatio(                    aspectRatio: _controller!.value.aspectRatio,                    child: VideoPlayer(_controller!),                  ),                ),              ),              _controller!.value.isPlaying == true                  ? SizedBox()                  : IgnorePointer(                      ignoring: true,                      child: Icon(                        Icons.play_arrow,                        size: 100,                        color: Colors.red,                      ),                    ),            ],          )        : Theme(            data: ThemeData(                cupertinoOverrideTheme:                    CupertinoThemeData(brightness: Brightness.dark)),            child: CupertinoActivityIndicator(radius: 30));  }}

上一篇:怎么在网吧服务器加好友?

下一篇:Linux源码版本深度解析,探索源码世界的奥秘