i have problem in Dismissible Widget. when you run this code :
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('appbar'),
),
body: const MyStatefulWidgetState(),
),
);
}
}
class MyStatefulWidgetState extends StatefulWidget {
const MyStatefulWidgetState({Key? key}) : super(key: key);
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidgetState> {
final List<String> items = List<String>.generate(10, (i) => "Item ${i 1}");
@override
Widget build(BuildContext context) {
return ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(
height: 2,
),
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return Dismissible(
key: Key(item),
onDismissed: (DismissDirection direction) {
//Remove the item from the data source.
setState(() {
items.removeAt(index);
});
},
child: Container(
height: 90,
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Text(item),
),
color: UniqueColorGenerator.getColor(),
),
);
},
);
}
}
class UniqueColorGenerator {
static Random random = Random();
static Color getColor() {
return Color.fromARGB(
255, random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
}
and when you Dismiss a container, after Container removed from list, all the container's color changed ( like reset the app or hot reload and get new color )
1 - why this happened?
2 - how can i fix this? so when i Dismiss container, the color of other container remain the same color?
thanks
CodePudding user response:
I am not too far into the optimizations of Flutter with keys so I am not sure why your key doesn't do anything but the reason this happens by my understanding is the setState call.
setState will cause the build function to be run again which in turn means that the itemBuilder function will have to be run again which means that you are generating a new color for your container each time the itemBuilder function runs (eventhough it's for the same item) which explains the behaviour you are seeing.
Now for changing that, you can go different ways, two of which are described here:
Option 1 - Generate color based on the item
The Random
constructor takes an optional seed allowing you to reproduce a given set of random values each time. If you use the item's hashCode, you will still generate an effectively random color per item:
class UniqueColorGenerator {
static Color getColor(String item) {
final random = Random(item.hashCode);
return Color.fromARGB(
255, random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
}
then use that for your Container color with color: UniqueColorGenerator.getColor(item),
. The advantage of this approach is that (at least with Strings as item) the colors are consistent even between restarts. For more complex objects, make sure you override the hashCode getter!
Option 2 - Make the colors part of the item state
To ensure you don't lose the information on which item had what colors, store it together with the items.
First, create an Item class to hold our data neatly together:
class Item {
final String text;
final Color color;
Item(this.text, this.color);
}
Next up, update the generation of the items to make use of that class:
final List<Item> items = List<Item>.generate(
10,
(i) => Item("Item ${i 1}", UniqueColorGenerator.getColor())
);
And lastly, update the usages of it (so the Container's color becomes item.color
, and what was previously item
is now item.text
).
With this approach, the colors won't be retained throughout restarts.