#flutter
#flutter
Вопрос:
Я хочу написать поставщик изображений для своего собственного класса изображений. Давайте возьмем приведенный ниже виджет в качестве образца для класса изображений. Этот виджет можно использовать всякий раз, когда требуется экземпляр изображения. Теперь я использую виджет, которому в качестве параметра требуется поставщик изображений. Как я могу создать поставщика изображений cusom? (Я знаю о существующих пакетах dart, но вопрос здесь в том, как написать свой собственный поставщик изображений)
class _AppImageState extends State<AppImage> {
Uint8List imageData;
Future download({iterate = 0}) async {
if (iterate >= 5) {
Log.w("too many iterations for ${widget.url}");
return;
}
var response;
try {
var request = await HttpClient().getUrl(Uri.parse(widget.url));
response = await request.close();
} catch (e) {
Log.e(e);
return Timer(Duration(seconds: iterate 1), () => download(iterate: iterate 1));
}
try {
if (response != null amp;amp; response.statusCode == 200) {
Uint8List bytes = await consolidateHttpClientResponseBytes(response);
setState(() {
imageData = bytes;
});
} else {
return Timer(Duration(seconds: iterate 1), () => download(iterate: iterate 1));
}
} catch (e) {
Log.e(e);
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
download();
}
@override
Widget build(BuildContext context) {
return imageData != null ? Image.memory(imageData) : widget.placeholder ?? Container();
}
}
Ответ №1:
Я следую FileImage
и пишу свой собственный ImageProvider, я не справляюсь с этим, так как это может вызвать проблемы (например, я не тестирую его с помощью gif), вы также можете прочитать FileImage
, это меньше кода, чем NetworkImage
и легко читается.
class CacheImageProvider extends ImageProvider<CacheImageProvider> {
final String fileId;//the cache id use to get cache
CacheImageProvider(this.fileId);
@override
ImageStreamCompleter load(CacheImageProvider key, DecoderCallback decode) {
return MultiFrameImageStreamCompleter(
codec: _loadAsync(decode),
scale: 1.0,
debugLabel: fileId,
informationCollector: () sync* {
yield ErrorDescription('Path: $fileId');
},
);
}
Future<Codec> _loadAsync(DecoderCallback decode) async {
// the DefaultCacheManager() encapsulation, it get cache from local storage.
final Uint8List bytes = await (await CacheThumbnail.getThumbnail(fileId)).readAsBytes();
if (bytes.lengthInBytes == 0) {
// The file may become available later.
PaintingBinding.instance?.imageCache?.evict(this);
throw StateError('$fileId is empty and cannot be loaded as an image.');
}
return await decode(bytes);
}
@override
Future<CacheImageProvider> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<CacheImageProvider>(this);
}
//the custom == and hashCode must be write, because the ImageProvider memory cache use it to identify the same image.
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) return false;
bool res = other is CacheImageProvider amp;amp; other.fileId == fileId;
return res;
}
@override
int get hashCode => fileId.hashCode;
@override
String toString() => '${objectRuntimeType(this, 'CacheImageProvider')}("$fileId")';
}
и использовать его:
Image(image: CacheImageProvider(_data[index].fileId))
Ответ №2:
Вот решение, которое я нашел. Я надеюсь, что это поможет вам
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class CacheImageProvider extends ImageProvider<CacheImageProvider> {
final String tag; //the cache id use to get cache
final Uint8List img; //the bytes of image to cache
CacheImageProvider(this.tag, this.img);
@override
ImageStreamCompleter load(CacheImageProvider key, DecoderCallback decode) {
return MultiFrameImageStreamCompleter(
codec: _loadAsync(decode),
scale: 1.0,
debugLabel: tag,
informationCollector: () sync* {
yield ErrorDescription('Tag: $tag');
},
);
}
Future<Codec> _loadAsync(DecoderCallback decode) async {
// the DefaultCacheManager() encapsulation, it get cache from local
storage.
final Uint8List bytes = img;
if (bytes.lengthInBytes == 0) {
// The file may become available later.
PaintingBinding.instance?.imageCache?.evict(this);
throw StateError('$tag is empty and cannot be loaded as an image.');
}
return await decode(bytes);
}
@override
Future<CacheImageProvider> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<CacheImageProvider>(this);
}
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) return false;
bool res = other is CacheImageProvider amp;amp; other.tag == tag;
return res;
}
@override
int get hashCode => tag.hashCode;
@override
String toString() =>
'${objectRuntimeType(this, 'CacheImageProvider')}("$tag")';
}
Ответ №3:
Для тех, кто ищет решение для добавления заголовков в веб-изображения Flutter, я основал свой класс на ответе @nillouise. Удивительно, но это работает!
String TOKEN;
String URLBASE;
class AuthImageProvider extends ImageProvider<AuthImageProvider> {
final String relativeUrl;
Future<http.Response> resp;
AuthImageProvider(this.relativeUrl) {
Map<String, String> h = {"Authorization": "bearer $TOKEN"};
resp = http.client.get(URLBASE relativeUrl, headers: h);
}
@override
ImageStreamCompleter load(AuthImageProvider key, decode) {
return MultiFrameImageStreamCompleter(
codec: _loadAsync(decode), scale: 1.0);
throw UnimplementedError();
}
Future<Codec> _loadAsync(DecoderCallback decode) async {
// the DefaultCacheManager() encapsulation, it get cache from local storage.
final bytes = (await resp).bodyBytes;
if (bytes.lengthInBytes == 0) {
// The file may become available later.
PaintingBinding.instance?.imageCache?.evict(this);
throw StateError(
'$relativeUrl is empty and cannot be loaded as an image.');
}
return await decode(bytes);
}
@override
Future<AuthImageProvider> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<AuthImageProvider>(this);
}
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) return false;
bool res = other is AuthImageProvider amp;amp; other.relativeUrl == relativeUrl;
return res;
}
@override
int get hashCode => relativeUrl.hashCode;
@override
String toString() =>
'${objectRuntimeType(this, 'CacheImageProvider')}("$relativeUrl")';
}