If you maintain a Flutter project long enough, the day comes when flutter analyze spits out hundreds of deprecated warnings. Everything works fine functionally, but when warnings pile up, real problems get buried. Here are the patterns from cleaning up 200+ deprecated warnings in one go.
Diagnosis: Assess the Situation with flutter analyze
flutter analyze --no-pub
Adding --no-pub skips pub package re-analysis for speed. Categorizing the output reveals that most warnings are a few repeating patterns.
info * 'withOpacity' is deprecated ... * lib/core/theme/app_theme.dart:45:22
info * 'value' is deprecated and shouldn't be used. Use 'initialValue' instead ...
info * 'activeColor' is deprecated ... Use 'activeThumbColor' instead.
warning * Unused import: 'package:go_router/go_router.dart' ...
Case 1: Color.withOpacity -> withValues(alpha:)
The most frequent deprecation. Almost all color opacity handling code is affected.
Before:
color: Colors.blue.withOpacity(0.5)
color: theme.accent.withOpacity(0.16)
border: Border.all(color: colors.border.withOpacity(0.3))
After:
color: Colors.blue.withValues(alpha: 0.5)
color: theme.accent.withValues(alpha: 0.16)
border: Border.all(color: colors.border.withValues(alpha: 0.3))
For many files, use sed to replace all at once.
# Bulk replacement across entire project (macOS)
find lib -name "*.dart" -exec sed -i '' 's/\.withOpacity(\([^)]*\))/.withValues(alpha: \1)/g' {} \;
Re-check with flutter analyze after replacement. Occasionally there are false positives if you have a custom method named withOpacity, so always review the results.
Case 2: DropdownButtonFormField.value -> initialValue
After Flutter 3.x, the initial value parameter name for DropdownButtonFormField changed.
Before:
DropdownButtonFormField<String>(
value: _selectedCategory,
items: ...,
onChanged: (v) => setState(() => _selectedCategory = v),
)
After:
DropdownButtonFormField<String>(
initialValue: _selectedCategory,
items: ...,
onChanged: (v) => setState(() => _selectedCategory = v),
)
There’s a subtle difference between value and initialValue. value is the controlled approach that always syncs with external state, while initialValue only sets the initial value. In most cases, switching to initialValue produces the same behavior.
Case 3: Switch.activeColor -> activeThumbColor
The Switch widget’s color properties were refined for Material 3.
Before:
Switch(
value: _isEnabled,
onChanged: _onToggle,
activeColor: Colors.blue,
)
After:
Switch(
value: _isEnabled,
onChanged: _onToggle,
activeThumbColor: Colors.blue,
)
If you want to change the track color too, add activeTrackColor. The old activeColor set both thumb and track to the same color, but the new API separates them.
Case 4: GoRouter location -> uri.toString()
When getting the current path in GoRouter, you need to use .uri instead of .location.
Before:
final currentPath = GoRouter.of(context)
.routeInformationProvider
.value
.location;
After:
final currentPath = GoRouter.of(context)
.routeInformationProvider
.value
.uri
.toString();
location was a String, and uri is a Uri object. For path comparison or startsWith usage, using uri.path without toString() is more appropriate.
Case 5: BuildContext async gap Warning
Using context after await in an async function triggers a warning. This is because the widget might be disposed after the await, and the context reference would be stale.
Problem code:
Future<void> _onPickImage() async {
final result = await ImagePicker().pickImage(source: ImageSource.gallery);
if (result != null) {
context.read<SomeBloc>().add(ImageSelected(result.path)); // warning
}
}
Fix:
Future<void> _onPickImage() async {
final result = await ImagePicker().pickImage(source: ImageSource.gallery);
if (!mounted) return; // <- added
if (result != null) {
context.read<SomeBloc>().add(ImageSelected(result.path));
}
}
Adding if (!mounted) return; right after await is the standard pattern.
Case 6: Miscellaneous Minor Warnings
Unnecessary string interpolation:
// Before (warning)
Text('${someVariable}')
Text('?id=${widget.id}') // braces unnecessary
// After
Text('$someVariable')
Text('?id=$widget.id') // but braces needed for property access
Text('?id=${widget.id}') // braces required in this case
Unnecessary toList():
// Before
...answers.toList().map((a) => Widget())
// After (spread operator accepts Iterable directly)
...answers.map((a) => Widget())
Null-safe operator misuse:
// Using ?. on a non-nullable variable
final list = <String>[];
list?.map(...) // warning: list is non-nullable
// Fix
list.map(...)
Summary: Priority Approach
- Run
flutter analyze --no-pubto assess the overall situation - Start with withOpacity – highest count and solvable with a single sed command
- Warning level (unused imports, unused variables) – manual fix per file
- Info level remaining deprecations – identify patterns by case then fix
- Re-run
flutter analyze --no-pubafter fixes to verify
Once cleaned up, maintaining it afterward is just a matter of checking flutter analyze results before merging PRs.

💬 댓글
비밀번호를 기억해두면 나중에 내 댓글을 삭제할 수 있어요.