The `findChildIndexCallback` parameter in `ListView.separated` and `SliverList.separated` constructors have been deprecated in favor of `findItemIndexCallback`. The new callback returns item indices directly, eliminating the need for manual index calculations to account for separators.
- Who is affected
- Code that still calls the deprecated API; it keeps working until removal but produces analyzer warnings. Code that uses ListView.separated, SliverList.separated.
- Practical impact
- Warnings now; removal in a future release. Plan the migration but no immediate break.
- What action should I take?
- Follow the official migration guide below, update affected call sites, run `dart fix --apply` where a fix is available, then run your tests.
Before and after (from the official guide)
| 1 | ListView.separated( | |
| 2 | itemCount: items.length, | |
| 3 | − | findChildIndexCallback: (Key key) { |
| 4 | final ValueKey<String> valueKey = key as ValueKey<String>; | |
| 5 | final int itemIndex = items.indexOf(valueKey.value); | |
| 6 | − | // Multiply by 2 to account for separators. |
| 7 | − | return itemIndex == -1 ? null : itemIndex * 2; |
| 8 | }, | |
| 9 | itemBuilder: (BuildContext context, int index) { | |
| 10 | return ListTile( | |
| 11 | key: ValueKey<String>(items[index]), | |
| 12 | title: Text(items[index]), | |
| 13 | ); | |
| 14 | }, | |
| 15 | separatorBuilder: (BuildContext context, int index) => const Divider(), | |
| 16 | ) |
| 1 | ListView.separated( | |
| 2 | itemCount: items.length, | |
| 3 | + | findItemIndexCallback: (Key key) { |
| 4 | final ValueKey<String> valueKey = key as ValueKey<String>; | |
| 5 | final int itemIndex = items.indexOf(valueKey.value); | |
| 6 | + | // Return item index directly - no need to multiply by 2. |
| 7 | + | return itemIndex == -1 ? null : itemIndex; |
| 8 | }, | |
| 9 | itemBuilder: (BuildContext context, int index) { | |
| 10 | return ListTile( | |
| 11 | key: ValueKey<String>(items[index]), | |
| 12 | title: Text(items[index]), | |
| 13 | ); | |
| 14 | }, | |
| 15 | separatorBuilder: (BuildContext context, int index) => const Divider(), | |
| 16 | ) |
Raw before / after
ListView.separated(
itemCount: items.length,
findChildIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final int itemIndex = items.indexOf(valueKey.value);
// Multiply by 2 to account for separators.
return itemIndex == -1 ? null : itemIndex * 2;
},
itemBuilder: (BuildContext context, int index) {
return ListTile(
key: ValueKey<String>(items[index]),
title: Text(items[index]),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)ListView.separated(
itemCount: items.length,
findItemIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final int itemIndex = items.indexOf(valueKey.value);
// Return item index directly - no need to multiply by 2.
return itemIndex == -1 ? null : itemIndex;
},
itemBuilder: (BuildContext context, int index) {
return ListTile(
key: ValueKey<String>(items[index]),
title: Text(items[index]),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)Official migration guide (excerpt, © The Flutter Authors, CC BY 3.0)
To migrate from findChildIndexCallback to findItemIndexCallback,
replace the parameter name and remove any index multiplications
that were used to account for separators.
Code before migration:
ListView.separated(
itemCount: items.length,
findChildIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final int itemIndex = items.indexOf(valueKey.value);
// Multiply by 2 to account for separators.
return itemIndex == -1 ? null : itemIndex * 2;
},
itemBuilder: (BuildContext context, int index) {
return ListTile(
key: ValueKey<String>(items[index]),
title: Text(items[index]),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)Code after migration:
ListView.separated(
itemCount: items.length,
findItemIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final int itemIndex = items.indexOf(valueKey.value);
// Return item index directly - no need to multiply by 2.
return itemIndex == -1 ? null : itemIndex;
},
itemBuilder: (BuildContext context, int index) {
return ListTile(
key: ValueKey<String>(items[index]),
title: Text(items[index]),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)The same migration applies to SliverList.separated:
Code before migration:
SliverList.separated(
itemCount: items.length,
findChildIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final int itemIndex = items.indexOf(valueKey.value);
return itemIndex == -1 ? null : itemIndex * 2;
},
itemBuilder: (BuildContext context, int index) {
return Container(
key: ValueKey<String>(items[index]),
child: Text(items[index]),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)Code after migration:
SliverList.separated(
itemCount: items.length,
findItemIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final int itemIndex = items.indexOf(valueKey.value);
return itemIndex == -1 ? null : itemIndex;
},
itemBuilder: (BuildContext context, int index) {
return Container(
key: ValueKey<String>(items[index]),
child: Text(items[index]),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.Listed in the official breaking-changes index; title states deprecation.
An official announcement or migration guide documents an intended behaviour or API change. A verified source change (git diff) shows code changed but does not by itself prove a public API is breaking. AI interpretations are labelled and never used to classify a change.
- Official migration guide
- ListView.separated
- SliverList.separated
- Deprecate findChildIndexCallback for separated constructors
- Source commit
- b3045439b7c0
- Source last updated
- Oct 21, 2026
- Last synchronized
- Oct 21, 2026
- Publication status
- published
Publication history
- Oct 21, 2026, 8:31 PM: new → published (ingestion) — Backed by an official breaking-change/migration guide.
AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.