在我的 flutter 应用程序中,我有一个屏幕显示带有 gif 的练习名称,列表太长,当我将 gif 添加到列表中时,gif 没有按预期播放,gif 只有 2 秒,当第一个 gif 时播放第一秒,它停止并等待,直到列表中的所有其他 gif 播放第一秒,当所有 gif 播放第一秒时,然后返回到第一个 gif 并播放第二个(第二个),并以这种方式重播 gif ,我该如何解决这个问题?
我使用了cached_network_images和Image.memory和Image.file,它们都有保存问题
列表视图代码:
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: exercises.length,
itemBuilder:
(BuildContext context, int index) =>
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
decoration: BoxDecoration(
color: theme.colorScheme.background,
border: Border.all(
width: 3,
color: theme.colorScheme
.tertiaryContainer,
),
borderRadius:
BorderRadius.circular(35),
),
child: ListTile(
minVerticalPadding: 0,
visualDensity: const VisualDensity(
vertical: 4,
),
title: Row(
children: [
SizedBox(
width: width * .1,
height: width * .1,
//......................................Display gifs here.................................
child: ImageLoader(
imageUrl: '$baseUrl${exercises[index]['gif']}'
),
),
SizedBox(width: width * .015),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SizedBox(
width: width * .5,
child: BigText(
text: Functions()
.getAvailableData(
lang: lang,
data:
exercises[index],
type: TranslationTypes
.name,
),
color: theme.cardColor,
fontSize: width * .026,
maxLines: 2,
height: 1.75,
textOverflow:
TextOverflow
.visible,
),
),
SizedBox(
height: width * .015,
),
exercises[index]
['muscle'] ==
null
? const SizedBox()
: Container(
height:
height * .03,
alignment: Alignment
.center,
padding:
const EdgeInsets
.symmetric(
horizontal: 20,
vertical: 5,
),
decoration:
BoxDecoration(
borderRadius:
BorderRadius
.circular(
1000),
color: const Color(
0xFF86EE75)
.withOpacity(
.15),
),
child: BigText(
text: Functions()
.getAvailableData(
lang: lang,
data: exercises[
index]
['muscle'],
type:
TranslationTypes
.name,
),
color: theme
.colorScheme
.outline,
fontSize:
width * .018,
),
),
],
),
],
),
trailing: Material(
borderRadius:
BorderRadius.circular(10000),
color:
theme.colorScheme.background,
child: InkWell(
onTap: () {
addAndRemoveFromExercises(
index);
},
borderRadius:
BorderRadius.circular(1000),
child: Container(
width: width * .065,
height: width * .065,
padding: EdgeInsets.all(
width * .020,
),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
10000),
border: Border.all(
width: 3,
color: theme.colorScheme
.tertiaryContainer,
),
),
child: selectedIds.contains(
exercises[index]
['id']) ==
true
? SvgPicture.asset(
'assets/icons/check.svg',
color:
theme.cardColor,
width: 25,
height: 25,
)
: const SizedBox(),
),
),
),
),
),
],
),
),
),
ImageLoader代码:
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'spinkit.dart';
class ImageLoader extends StatelessWidget {
const ImageLoader({
Key? key,
required this.imageUrl,
this.borderRadius,
this.errorHeight,
this.errorWidth,
this.fit,
this.color,
this.id,
this.width,
this.height,
}) : super(key: key);
final String imageUrl;
final BorderRadius? borderRadius;
final double? errorHeight, errorWidth, width, height;
final BoxFit? fit;
final String? id;
final Color? color;
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: borderRadius ?? BorderRadius.circular(10),
child: CachedNetworkImage(
fit: fit ?? BoxFit.fill,
height: height,
width: width,
color: color,
cacheKey: id,
imageUrl: imageUrl,
errorWidget: (context, url, exc) {
return Center(
child: Icon(
Icons.error,
color: Colors.red.withOpacity(0.7),
size: 30,
),
);
},
placeholder: (context, url) {
return const Spinkit();
},
),
);
}
}
当所有GIF都相同时没有问题,只有当GIF不同时才会出现问题
这里有几种解决这个问题的方法:
预加载图像:您可以考虑预加载它们,而不是仅在 GIF 进入视图时加载它们。这可能会占用大量资源,并且不建议将其用于包含许多 GIF 的长列表,但如果您的列表易于管理,则这可以确保所有 GIF 均已完全加载并准备好播放。您可以为此使用 precacheImage 函数。
使用专用的 GIF 库:不要使用标准的图像显示小部件,而是考虑使用专用于更好地处理 GIF 的包,例如 flutter_gifimage。这些库通常可以更好地控制 GIF 动画,并可能以避免当前问题的方式处理渲染。
自定义滚动物理:为 ListView.builder 实现自定义滚动物理,减少或消除 GIF 的离屏优化。这是一种更高级的解决方案,可能会导致性能问题,但它允许您保持 GIF 运行,即使它们不在直接视口中也是如此。
优化和缩小尺寸:确保您的 GIF 已优化且不会太大。 GIF 越大、越复杂,Flutter 就越难在列表中管理它们。降低帧速率或尺寸可能会有所帮助。
替代动画格式:考虑动画是否需要是 GIF。在某些情况下,将 GIF 转换为 MP4 等视频格式并使用视频播放器(如 flutter_video_player)可能会更有效。这是因为视频格式通常可以更好地优化播放,并且可以比 GIF 更有效地暂停和恢复。
一次显示一个 GIF:修改设计以一次仅显示一个动画 GIF,而其他 GIF 则暂停或替换为静态图像,直到用户与它们交互。这大大减少了渲染引擎的负载。
自定义 GIF 播放器:实现自定义 GIF 播放器,可以更好地处理列表中 GIF 的生命周期和播放。这可能涉及根据 GIF 在视口中的可见性对 GIF 何时开始和停止进行更详细的控制。
状态管理:确保应用程序的状态管理不会导致小部件不必要的重建,这可能会重置 GIF 动画。使用 Provider 或 Bloc 等工具有效管理状态,而不会导致不需要的重建。