Chrome DevTools network Tab
example video
As you can see in the example video, when a category is selected from the space on the left, the corresponding items are displayed on the screen. The main issue is the delay that occurs when switching categories, even though the images have already been loaded and cached.
I believe this delay is caused by the time it takes to retrieve the cached images from memory. I have tried numerous methods to preload the widgets, but all attempts have failed.
While experimenting, I happened to look at the network tab in Chrome DevTools and noticed that the images were coming in through network requests, not from the cache. It appears that CachedNetworkImage is not functioning properly.
Here is my code about cachedNetworkImage.
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black, width: 2.0),
borderRadius: BorderRadius.circular(10.0)),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: CachedNetworkImage(
key: ValueKey(tileData['imageCode']),
cacheKey: tileData['imageCode'],
imageUrl: widget.menuData['imageCode']
[tileData['imageCode']],
cacheManager: CustomCacheManager.instance,
fit: BoxFit.cover)))
class CustomCacheManager {
static const key = 'imageCache';
static CacheManager instance = CacheManager(
Config(
key,
stalePeriod: const Duration(days: 1),
maxNrOfCacheObjects: 100, // 최대 캐시 객체 수를 100개로 제한
repo: JsonCacheInfoRepository(databaseName: key),
fileService: HttpFileService(),
),
);
}
there is full code
void _menuPreRender() {
_menuWidgets.clear();
for (Map<String, dynamic> category in _menuData['toManageList']) {
_menuWidgets[category['name']] = MenuView(
key: ValueKey(category['name']),
menuData: _menuData,
category: category['name'],
updateCallback: (int selectedMenuIndex) {
return () {
setState(() {
_selectedMenu = selectedMenuIndex;
_mainAreaWidget = _menuEdit(isEdit: true);
});
};
},
setManageMenuData: (Map<String, dynamic> data) {
_setManageMenuData(data);
});
}
}
/* ... */
class MenuView extends StatefulWidget {
const MenuView(
{super.key,
required this.menuData,
required this.category,
required this.updateCallback,
required this.setManageMenuData});
final String category;
final Map<String, dynamic> menuData;
final Function(int selectedMenuIndex) updateCallback;
final Function(Map<String, dynamic>) setManageMenuData;
@override
State<MenuView> createState() => _MenuViewState();
}
class _MenuViewState extends State<MenuView>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
for (var menu in widget.menuData['toManage'][widget.category]['menu']) {
if (menu['imageCode'] != null && menu['imageCode'] != '') {
precacheImage(
NetworkImage(widget.menuData['imageCode'][menu['imageCode']]),
context);
}
}
}
@override
Widget build(BuildContext context) {
super.build(context);
print('category: ${widget.category}');
double screenHeight = MediaQuery.of(context).size.height;
return ReorderableListView.builder(
buildDefaultDragHandles: false,
itemCount: widget.menuData['toManage'][widget.category]['menu'].length,
itemBuilder: (context, index) {
Map<String, dynamic> tileData =
widget.menuData['toManage'][widget.category]['menu'][index];
return ListTile(
key: Key('$index'),
title: SizedBox(
height: screenHeight * 0.15,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tileData['name'],
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
const SizedBox(height: 5),
Text(
tileData['description'],
style:
const TextStyle(fontSize: 15, color: Colors.grey),
),
const SizedBox(height: 5),
Text(
'${tileData['price']}원',
style: const TextStyle(fontSize: 20),
),
],
),
SizedBox(
width: screenHeight * 0.14,
height: screenHeight * 0.14,
child: tileData['imageCode'] != null
? Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black, width: 2.0),
borderRadius: BorderRadius.circular(10.0)),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: CachedNetworkImage(
key: ValueKey(tileData['imageCode']),
cacheKey: tileData['imageCode'],
imageUrl: widget.menuData['imageCode']
[tileData['imageCode']],
cacheManager: CustomCacheManager.instance,
fit: BoxFit.cover)))
: const SizedBox.shrink()),
],
),
),
onTap: widget.updateCallback(index),
trailing: Container(
width: screenHeight * 0.08,
alignment: Alignment.bottomCenter, // Container 내부의 아이콘을 중앙에 배치
child: ReorderableDragStartListener(
index: index,
child: Icon(Icons.drag_handle_rounded,
size: screenHeight * 0.08)),
));
},
onReorder: (oldIndex, newIndex) {
List<Map<String, dynamic>> menuList =
widget.menuData['toManage'][widget.category]['menu'];
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final Map<String, dynamic> item = menuList.removeAt(oldIndex);
menuList.insert(newIndex, item);
});
widget.setManageMenuData(widget.menuData['toManage']);
},
);
}
}
What I want is for the images that have already been loaded to be displayed to the users instantly without any delay when switching categories. I believe there must be a way to achieve this since many commercial apps support similar functionality.
한경완 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.