I am creating an application where there is a list of items in a ListView. Each item has a description and a photo. Each item is downloaded by my api and the ListView builder generates a test widget "TestInternalWidget" for each item with a photo generated again by FutureBuilder. In a real application, the fetchPhoto method returns the Uint8list photo. For simulation purposes I simply return the url. It works fine. However, there is a problem when deleting an item from the list. The element is removed, but the photo is not. For example: I want to delete item 2: The description is deleted, but, the picture from item 2 jumps to item 3, etc.
I will be grateful for your help. I am using getx for state management, but I checked in standard configuration with setstate() and there was the same problem
main.dart
import 'package:camera_app/views/widgets/testwidget.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'controllers/testcontroller.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final TestController testController = Get.put(TestController());
return GetMaterialApp(
title: 'test',
home: Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black54),
backgroundColor: Color(0xfffee6dc),
centerTitle: true,
),
backgroundColor: Color(0xfffff6f7),
body: Obx(() => ListView.builder(
cacheExtent: 100,
addAutomaticKeepAlives: true,
physics: BouncingScrollPhysics(),
//physics : NeverScrollableScrollPhysics(),
itemCount: testController.albumList.length,
itemExtent: 120,
itemBuilder: (context, index) {
print("item build");
return InkWell(
onDoubleTap: () {
testController.albumList.removeAt(index);
},
child: Obx(()=> TestInternalWidget(testController.albumList[index]))
);
})
)
)
);
}
}
testcontroller.dart
import 'dart:convert';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
//MODEL CLASS
class Album {
final int userId;
final int id;
final String title;
String ? url;
Album({
required this.userId,
required this.id,
required this.title,
this.url
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
List<Album> AlbumFromJson(String str) =>
List<Album>.from(json.decode(str).map((x) => Album.fromJson(x)));
class TestController extends GetxController {
var albumList = <Album>[].obs;
@override
void onInit() {
print("init controller");
fetchItems();
super.onInit();
}
Future<void> fetchItems() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/'));
List<Album> listAlbum;
if (response.statusCode == 200) {
listAlbum = AlbumFromJson(response.body);
//Adding sample url for every item
for(int i = 0; i< listAlbum.length; i++){
listAlbum[i].url = 'https://picsum.photos/250?image=' + i.toString();
}
albumList.addAll(listAlbum);
} else {
throw Exception('Failed to load album');
}
}
}
testwidget.dart
import 'package:flutter/material.dart';
import '../../controllers/testcontroller.dart';
class TestInternalWidget extends StatefulWidget {
Album album;
TestInternalWidget(this.album);
@override
TestInternalWidgetState createState() => TestInternalWidgetState();
}
class TestInternalWidgetState extends State<TestInternalWidget>
{
Future<String?> fetchPhoto() async
{
//here for test I'm returning only string url, but in real Uint8List object from my backend api
return widget.album.url;
}
late Future<String?> myFuture;
@override
void initState() {
myFuture = fetchPhoto();
super.initState();
}
@override
Widget build(BuildContext context) {
print("internal widget build");
return Container(
child:Column(
children: [
FutureBuilder(
future: myFuture,
builder: (context, snapshot) {
String url = snapshot.data as String;
return snapshot.hasData && snapshot.data != null
?
CircleAvatar(
radius: 30.0,
backgroundImage:
NetworkImage(url),
backgroundColor: Colors.transparent,
)
: CircularProgressIndicator();
},
),
Text(widget.album.title),
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: Color(0xffE4CFC6)
)
);
}
}

