I am trying to create a list of cards representing categories and I opted to use a custom widget instead of the provided Card widget so I can use images and apply rounded borders to them and I found that using Container does just that, the Ink and InkWell widgets are used to show the ripple effect on tapped.
This is the code for the screen
class CategoriesScreen extends ConsumerWidget {
const CategoriesScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final categoriesNavigationKey = ref.read(categoriesNavigationKeyProvider);
return PopScope(
canPop: false,
onPopInvokedWithResult: (route, result) =>
categoriesNavigationKey.currentState!.maybePop(),
child: Navigator(
key: categoriesNavigationKey,
initialRoute: '/',
onGenerateRoute: (settings) {
if (settings.name != null) {
final String routeName = settings.name!;
if (routeName == '/categoryDetails') {
return CupertinoPageRoute<void>(
settings: settings,
builder: (context) => CategoryDetailsScreen(
category: Category.fromJson(
settings.arguments as Map<String, dynamic>,
),
),
);
}
}
return CupertinoPageRoute<void>(
settings: settings,
builder: (context) => const _CategoriesList(),
);
},
),
);
}
}
Categories List:
class _CategoriesList extends ConsumerWidget {
const _CategoriesList();
@override
Widget build(BuildContext context, WidgetRef ref) {
final textTheme = Theme.of(context).textTheme;
final categoriesScreenController = ref.watch(categoriesControllerProvider);
return categoriesScreenController.maybeWhen(
orElse: () {
return Center(child: CircularProgressIndicator());
},
data: (categories) {
return Scrollbar(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16,
children: [
Text("Toutes nos catégories", style: textTheme.titleLarge),
for (final category in categories)
CategoryItem(category: category),
],
),
),
),
);
},
);
}
}
CategoryItem :
class CategoryItem extends ConsumerWidget {
final Category category;
final BorderRadius _borderRadius = const BorderRadius.all(
Radius.circular(16),
);
const CategoryItem({super.key, required this.category});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Ink(
decoration: BoxDecoration(
borderRadius: _borderRadius,
color: Theme.of(context).colorScheme.surface,
boxShadow: kElevationToShadow[3],
),
child: InkWell(
onTap: () => ref
.read(categoriesNavigationKeyProvider)
.currentState
?.pushNamed('/categoryDetails', arguments: category.toJson()),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
clipBehavior: Clip.antiAlias,
width: double.infinity,
decoration: BoxDecoration(borderRadius: _borderRadius),
child: Image.memory(
category.image,
fit: BoxFit.cover,
height: 200,
),
),
Padding(
padding: const EdgeInsets.all(22),
child: Text(
category.name,
style: Theme.of(
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
),
],
),
),
);
}
}
Result (captured on a real device and on a release build) : https://streamable.com/et9scf
In the provided small video you can see that the list scrolling animation kind of decomposes the widget although it's altogether a one whole widget, this issue is clearly seen when tapping back to the main route on the Categories screen's navigator. Am I missing something here or is it an engine/framework issue?