【问题标题】:Compress or Resize image before rendering in flutter在颤动渲染之前压缩或调整图像大小
【发布时间】:2020-12-31 08:25:27
【问题描述】:

我加载所有图像目录并加载我加载的目录中的所有图像路径。 (与storage_path

我使用文件路径加载图像,所以我使用Image.file()

但是,当我加载大图像文件(4032×3024 大小或 >3MB)时,加载非常缓慢。

像这样:

我不需要加载高分辨率的图像,因为图像小部件很小。

如何压缩或调整这些图像的大小?

或者有没有更好的解决方案?

代码:

// gallery_page.dart
import 'dart:collection';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:listing/widget/bar_widget.dart';
import 'package:listing/provider/dark_mode_provider.dart';
import 'package:listing/page/sub/image/image_edit_page.dart';
import 'package:listing/page/sub/gallery/media_directory.dart';
import 'package:listing/util/image_types.dart';
import 'package:provider/provider.dart';
import 'package:storage_path/storage_path.dart';

enum GalleryType { IMAGE, VIDEO }

class GalleryPageArguments {
  final GalleryType type;
  GalleryPageArguments(this.type);
}

class GalleryPage extends StatelessWidget {
  static final routeName = '/gallery_page';

  @override
  Widget build(BuildContext context) {
    GalleryPageArguments arguments = ModalRoute.of(context).settings.arguments;

    GalleryType type = arguments.type;
    ColorPalette palette = Provider.of<DarkModeProvider>(context).colorPallette;

    Future<List<MediaDirectory>> getPath;
    if(type == GalleryType.IMAGE) {
      getPath = _getImagePaths();
    } else {
      getPath = _getVideoPaths();
    }

    return Scaffold(
      body: SafeArea(
        child: FutureBuilder<List<MediaDirectory>>(
          future: getPath,
          builder: (context, snapshot) {
            if(snapshot.hasData) {
              HashMap<String, MediaDirectory> mediaDirsMap = new HashMap<String, MediaDirectory>();

              List<MediaDirectory> mediaDirs = snapshot.data;
              for(MediaDirectory mediaDir in mediaDirs) {
                mediaDirsMap.putIfAbsent(mediaDir.dirName, () => mediaDir);
              }

              return _InnerGalleryPage(palette, mediaDirsMap);
            } else {
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
      ),
    );
  }
  
  Future<List<MediaDirectory>> _getImagePaths() async {
    String imagesPath = await StoragePath.imagesPath;
    dynamic response = jsonDecode(imagesPath);
    List<dynamic> imageDirJsonList = List.from(response);
    
    List<MediaDirectory> imageDirList = imageDirJsonList.map((imageDirJson) => MediaDirectory.fromJson(imageDirJson, GalleryType.IMAGE)).toList();
    return imageDirList;
  }

  Future<List<MediaDirectory>> _getVideoPaths() async {
    String videoPath = await StoragePath.videoPath;
    dynamic response = jsonDecode(videoPath);
    List<dynamic> videoDirJsonList = List.from(response);
    
    List<MediaDirectory> imageDirList = videoDirJsonList.map((imageDirJson) => MediaDirectory.fromJson(imageDirJson, GalleryType.VIDEO)).toList();
    return imageDirList;
  }
}

class _InnerGalleryPage extends StatefulWidget {
  final ColorPalette _palette;
  final HashMap<String, MediaDirectory> _mediaDirs;

  _InnerGalleryPage(this._palette, this._mediaDirs);

  @override
  _InnerGalleryPageState createState() => _InnerGalleryPageState();
}

class _InnerGalleryPageState extends State<_InnerGalleryPage> {
  String currentSelectedDir;

  @override
  void initState() {
    super.initState();
    String firstDir = widget._mediaDirs.keys.toList()[0];
    currentSelectedDir = widget._mediaDirs[firstDir].dirName;
  }

  @override
  Widget build(BuildContext context) {
    HashMap<String, MediaDirectory> mediaDirs = widget._mediaDirs;

    return BarWidget(
      titleWidget: DropdownButtonHideUnderline(
        child: DropdownButton<String>(
          value: currentSelectedDir,
          items: mediaDirs.keys.map(
              (mediaDirName) {
                return DropdownMenuItem(
                  value: mediaDirName,
                  child: Text(mediaDirName),
                );
              }
            ).toList(),
          onChanged: (changedDir) {
            setState(() {
              currentSelectedDir = changedDir;
            });
          },
        )
      ),
      palette: widget._palette,
      child: Container(
        child: GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
            childAspectRatio: 1,
            crossAxisSpacing: 5,
            mainAxisSpacing: 5
          ),
          itemBuilder: (context, index) {
            String imagePath = mediaDirs[currentSelectedDir].mediaFiles[index].path;
            ImageTypes imageType = getImageTypesFromPath(imagePath);

            return GestureDetector(
              child: _getImage(imagePath),
              onTap: () {
                if(imageType == ImageTypes.GIF) {
                  File imageFile = File(imagePath);
                  Image pickedImage = Image.file(imageFile);
                  Navigator.pop(context, pickedImage);
                } else {
                  File imageFile = File(imagePath);
                  Image pickedImage = Image.file(imageFile);
                  Navigator.pushNamed(context, ImageEditPage.routeName, arguments: ImageEditPageArguments(pickedImage, imagePath, imageType)).then((result) {
                    if(result is Image) {
                      Navigator.pop(context, result);
                    }
                  });
                }
              }
            );
          },
          itemCount: mediaDirs[currentSelectedDir].mediaFilesCount,
        )
      ),
    );
  }

  Image _getImage(String filePath) {
    File imageFile = File(filePath);
    Image image = Image.file(imageFile, fit: BoxFit.cover);
    return image;
  }
}
// media_directory.dart
import 'dart:convert';

import 'package:listing/page/sub/gallery/gallery_page.dart';
import 'package:listing/page/sub/gallery/media_file.dart';

class MediaDirectory {
  final String _dirName;
  final List<MediaFile> _mediaFiles;

  String get dirName => _dirName;
  int get mediaFilesCount => _mediaFiles.length;
  List<MediaFile> get mediaFiles => _mediaFiles;

  MediaDirectory(this._dirName, this._mediaFiles);

  factory MediaDirectory.fromJsonString(String jsonString, GalleryType type) {
    return MediaDirectory.fromJson(jsonDecode(jsonString), type);
  }

  factory MediaDirectory.fromJson(dynamic json, GalleryType type) {
    String dirName = json['folderName'];
    List<MediaFile> mediaFiles = [];

    if(type == GalleryType.IMAGE) {
      List<String> paths = List.from(json['files']);
      mediaFiles = paths.map((path) => ImageFile(path)).toList();
    } else if(type == GalleryType.VIDEO) {
      List<dynamic> files = List.from(json['files']);
      mediaFiles = files.map((fileJson) => VideoFile.fromJson(fileJson)).toList();
    }

    return MediaDirectory(dirName, mediaFiles);
  }
}
// media_file.dart
import 'dart:convert';

import 'package:flutter/material.dart';

class MediaFile {
  final String _path;

  String get path => _path;

  MediaFile(this._path);
}

class ImageFile extends MediaFile {
  ImageFile(String path) : super(path);
}

class VideoFile extends MediaFile {
  final String _fileName;
  final int _addedDate;
  final int _duration;
  final int _size;

  String get fileName => _fileName;
  int get addedDate => _addedDate;
  int get duration => _duration;
  int get size => _size;

  VideoFile({
    @required String path,
    @required String fileName,
    @required int addedDate,
    @required int duration,
    @required int size
  })
  : assert(path != null),
    assert(fileName != null),
    assert(addedDate != null),
    assert(duration != null),
    assert(size != null),
    
    this._fileName = fileName,
    this._addedDate = addedDate,
    this._duration = duration,
    this._size = size,
    
    super(path);

  factory VideoFile.fromJsonString(String jsonString) {
    return VideoFile.fromJsonString(jsonDecode(jsonString));
  }

  factory VideoFile.fromJson(dynamic json) {
    String path = json['path'];
    String fileName = json['displayName'];
    int addedDate = int.parse(json['dateAdded']);
    int duration = int.parse(json['duration']);
    int size = int.parse(json['size']);
    return VideoFile(path: path, fileName: fileName, addedDate: addedDate, duration: duration, size: size);
  }
}

如果你需要其他代码来解决这个问题,我可以给你你需要的代码。

谢谢。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    您应该使用缩略图加载网格图像,而不是实际图像。试试用这个,photo_manager:

    要么被分页:

    final assetList = await path.getAssetListPaged(page, perPage);
    

    或远程:

    final assetList = await path.getAssetListRange(start: 0, end: 88);
    

    之后,获取 entity.thumbData 以显示缩略图:

    Uint8List thumbBytes = await entity.thumbData;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-30
      • 1970-01-01
      • 2019-12-29
      • 1970-01-01
      • 1970-01-01
      • 2020-06-16
      • 2018-01-18
      • 1970-01-01
      相关资源
      最近更新 更多