Initial commit
This commit is contained in:
+72
@@ -0,0 +1,72 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
build/
|
||||
|
||||
# Android related
|
||||
**/android/**/gradle-wrapper.jar
|
||||
**/android/.gradle
|
||||
**/android/captures/
|
||||
**/android/gradlew
|
||||
**/android/gradlew.bat
|
||||
**/android/local.properties
|
||||
**/android/**/GeneratedPluginRegistrant.java
|
||||
|
||||
# iOS/XCode related
|
||||
**/ios/**/*.mode1v3
|
||||
**/ios/**/*.mode2v3
|
||||
**/ios/**/*.moved-aside
|
||||
**/ios/**/*.pbxuser
|
||||
**/ios/**/*.perspectivev3
|
||||
**/ios/**/*sync/
|
||||
**/ios/**/.sconsign.dblite
|
||||
**/ios/**/.tags*
|
||||
**/ios/**/.vagrant/
|
||||
**/ios/**/DerivedData/
|
||||
**/ios/**/Icon?
|
||||
**/ios/**/Pods/
|
||||
**/ios/**/.symlinks/
|
||||
**/ios/**/profile
|
||||
**/ios/**/xcuserdata
|
||||
**/ios/.generated/
|
||||
**/ios/Flutter/App.framework
|
||||
**/ios/Flutter/Flutter.framework
|
||||
**/ios/Flutter/Generated.xcconfig
|
||||
**/ios/Flutter/app.flx
|
||||
**/ios/Flutter/app.zip
|
||||
**/ios/Flutter/flutter_assets/
|
||||
**/ios/ServiceDefinitions.json
|
||||
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!**/ios/**/default.mode1v3
|
||||
!**/ios/**/default.mode2v3
|
||||
!**/ios/**/default.pbxuser
|
||||
!**/ios/**/default.perspectivev3
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
@@ -0,0 +1,10 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: b712a172f9694745f50505c93340883493b505e5
|
||||
channel: stable
|
||||
|
||||
project_type: package
|
||||
@@ -0,0 +1,9 @@
|
||||
## [0.0.1] - TODO: Add release date.
|
||||
|
||||
* TODO: Describe initial release.
|
||||
|
||||
## 1.0.0
|
||||
* init release
|
||||
|
||||
## 1.0.1
|
||||
* add check mounted when setState
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Jpeng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,86 @@
|
||||
# flutter_gifimage
|
||||
|
||||
We should know that in order to achieve Gif in flutter, we can use Image, but we have no way to manipulate Gif, for example: change its speed, control it has been playing in a frame,
|
||||
in which frame range loop. These problems can be solved by this widget,it also help you contain gif cache,avoid load frame every time.
|
||||
|
||||
# Screenshots
|
||||
|
||||

|
||||
|
||||
# Usage(Simple)
|
||||
add in pubspec
|
||||
|
||||
```dart
|
||||
|
||||
flutter_gifimage: ^1.0.0
|
||||
|
||||
```
|
||||
|
||||
simple usage
|
||||
|
||||
```dart
|
||||
GifController controller= GifController(vsync: this);
|
||||
|
||||
|
||||
GifImage(
|
||||
controller: controller,
|
||||
image: AssetImage("images/animate.gif"),
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
list the most common operate in GifController:
|
||||
|
||||
|
||||
```dart
|
||||
// loop from 0 frame to 29 frame
|
||||
controller.repeat(min:0,max:29,period:Duration(millseconds:300));
|
||||
|
||||
// jumpTo thrid frame(index from 0)
|
||||
controller.value = 0;
|
||||
|
||||
// from current frame to 26 frame
|
||||
controller.animateTo(26);
|
||||
|
||||
```
|
||||
|
||||
If you need to preCache gif,try this
|
||||
|
||||
```dart
|
||||
// put imageProvider
|
||||
fetchGif(AssetImage("images/animate.gif"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
# Thanks
|
||||
* [gif_ani](https://github.com/hyz1992/gif_ani) (thanks for giving me idea)
|
||||
|
||||
# License
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Jpeng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
author: Jpeng
|
||||
email: peng8350@gmail.com
|
||||
time:2019-7-26 3:30
|
||||
*/
|
||||
|
||||
library flutter_gifimage;
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:ui' as ui show Codec;
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// cache gif fetched image
|
||||
class GifCache {
|
||||
final Map<String, List<ImageInfo>?> caches = Map();
|
||||
|
||||
void clear() {
|
||||
caches.clear();
|
||||
}
|
||||
|
||||
bool evict(Object key) {
|
||||
final List<ImageInfo>? pendingImage = caches.remove(key);
|
||||
if (pendingImage != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// controll gif
|
||||
class GifController extends AnimationController {
|
||||
GifController(
|
||||
{required TickerProvider vsync,
|
||||
double value = 0.0,
|
||||
Duration? reverseDuration,
|
||||
Duration? duration,
|
||||
AnimationBehavior? animationBehavior})
|
||||
: super.unbounded(
|
||||
value: value,
|
||||
reverseDuration: reverseDuration,
|
||||
duration: duration,
|
||||
animationBehavior: animationBehavior ?? AnimationBehavior.normal,
|
||||
vsync: vsync);
|
||||
|
||||
@override
|
||||
void reset() {
|
||||
value = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
class GifImage extends StatefulWidget {
|
||||
GifImage({
|
||||
required this.image,
|
||||
required this.controller,
|
||||
this.semanticLabel,
|
||||
this.excludeFromSemantics = false,
|
||||
this.width,
|
||||
this.height,
|
||||
this.onFetchCompleted,
|
||||
this.color,
|
||||
this.colorBlendMode,
|
||||
this.fit,
|
||||
this.alignment = Alignment.center,
|
||||
this.repeat = ImageRepeat.noRepeat,
|
||||
this.centerSlice,
|
||||
this.matchTextDirection = false,
|
||||
this.gaplessPlayback = false,
|
||||
});
|
||||
final VoidCallback? onFetchCompleted;
|
||||
final GifController controller;
|
||||
final ImageProvider image;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final Color? color;
|
||||
final BlendMode? colorBlendMode;
|
||||
final BoxFit? fit;
|
||||
final AlignmentGeometry alignment;
|
||||
final ImageRepeat repeat;
|
||||
final Rect? centerSlice;
|
||||
final bool matchTextDirection;
|
||||
final bool gaplessPlayback;
|
||||
final String? semanticLabel;
|
||||
final bool excludeFromSemantics;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return new GifImageState();
|
||||
}
|
||||
|
||||
static GifCache cache = GifCache();
|
||||
}
|
||||
|
||||
class GifImageState extends State<GifImage> {
|
||||
List<ImageInfo>? _infos;
|
||||
int _curIndex = 0;
|
||||
bool _fetchComplete = false;
|
||||
ImageInfo? get _imageInfo {
|
||||
if (!_fetchComplete) return null;
|
||||
return _infos == null ? null : _infos![_curIndex];
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.controller.addListener(_listener);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
widget.controller.removeListener(_listener);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(GifImage oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.image != oldWidget.image) {
|
||||
fetchGif(widget.image).then((imageInfors) {
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_infos = imageInfors;
|
||||
_fetchComplete = true;
|
||||
_curIndex = widget.controller.value.toInt();
|
||||
if (widget.onFetchCompleted != null) {
|
||||
widget.onFetchCompleted!();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (widget.controller != oldWidget.controller) {
|
||||
oldWidget.controller.removeListener(_listener);
|
||||
widget.controller.addListener(_listener);
|
||||
}
|
||||
}
|
||||
|
||||
void _listener() {
|
||||
if (_curIndex != widget.controller.value && _fetchComplete) {
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_curIndex = widget.controller.value.toInt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
if (_infos == null) {
|
||||
fetchGif(widget.image).then((imageInfors) {
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_infos = imageInfors;
|
||||
_fetchComplete = true;
|
||||
_curIndex = widget.controller.value.toInt();
|
||||
if (widget.onFetchCompleted != null) {
|
||||
widget.onFetchCompleted!();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final RawImage image = new RawImage(
|
||||
image: _imageInfo?.image,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
scale: _imageInfo?.scale ?? 1.0,
|
||||
color: widget.color,
|
||||
colorBlendMode: widget.colorBlendMode,
|
||||
fit: widget.fit,
|
||||
alignment: widget.alignment,
|
||||
repeat: widget.repeat,
|
||||
centerSlice: widget.centerSlice,
|
||||
matchTextDirection: widget.matchTextDirection,
|
||||
);
|
||||
if (widget.excludeFromSemantics) return image;
|
||||
return new Semantics(
|
||||
container: widget.semanticLabel != null,
|
||||
image: true,
|
||||
label: widget.semanticLabel == null ? '' : widget.semanticLabel,
|
||||
child: image,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final HttpClient _sharedHttpClient = HttpClient()..autoUncompress = false;
|
||||
|
||||
HttpClient get _httpClient {
|
||||
HttpClient client = _sharedHttpClient;
|
||||
assert(() {
|
||||
if (debugNetworkImageHttpClientProvider != null)
|
||||
client = debugNetworkImageHttpClientProvider!();
|
||||
return true;
|
||||
}());
|
||||
return client;
|
||||
}
|
||||
|
||||
Future<List<ImageInfo>?> fetchGif(ImageProvider provider) async {
|
||||
List<ImageInfo>? infos = [];
|
||||
late dynamic data;
|
||||
String key = provider is NetworkImage
|
||||
? provider.url
|
||||
: provider is AssetImage
|
||||
? provider.assetName
|
||||
: provider is MemoryImage
|
||||
? provider.bytes.toString()
|
||||
: "";
|
||||
if (GifImage.cache.caches.containsKey(key)) {
|
||||
infos = GifImage.cache.caches[key];
|
||||
return infos;
|
||||
}
|
||||
if (provider is NetworkImage) {
|
||||
final Uri resolved = Uri.base.resolve(provider.url);
|
||||
final HttpClientRequest request = await _httpClient.getUrl(resolved);
|
||||
provider.headers?.forEach((String name, String value) {
|
||||
request.headers.add(name, value);
|
||||
});
|
||||
final HttpClientResponse response = await request.close();
|
||||
data = await consolidateHttpClientResponseBytes(
|
||||
response,
|
||||
);
|
||||
} else if (provider is AssetImage) {
|
||||
AssetBundleImageKey key = await provider.obtainKey(ImageConfiguration());
|
||||
data = await key.bundle.load(key.name);
|
||||
} else if (provider is FileImage) {
|
||||
data = await provider.file.readAsBytes();
|
||||
} else if (provider is MemoryImage) {
|
||||
data = provider.bytes;
|
||||
}
|
||||
|
||||
ui.Codec codec = await PaintingBinding.instance
|
||||
.instantiateImageCodec(data.buffer.asUint8List());
|
||||
infos = [];
|
||||
for (int i = 0; i < codec.frameCount; i++) {
|
||||
FrameInfo frameInfo = await codec.getNextFrame();
|
||||
//scale ??
|
||||
infos.add(ImageInfo(image: frameInfo.image));
|
||||
}
|
||||
GifImage.cache.caches.putIfAbsent(key, () => infos);
|
||||
return infos;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
sdks:
|
||||
dart: ">=2.14.0 <3.0.0"
|
||||
@@ -0,0 +1,14 @@
|
||||
name: flutter_gifimage
|
||||
description: a gifimage for flutter,for solving gif cannot be controlled speed,progress
|
||||
version: 1.0.1
|
||||
homepage: https://github.com/peng8350/flutter_gifimage
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
dev_dependencies:
|
||||
flutter:
|
||||
Reference in New Issue
Block a user