Open5
SliverListとは?
以下サンプルコード
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Grid & List Sample',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('ショッピングアプリサンプル'),
),
body: CustomScrollView(
slivers: [
// カテゴリーグリッドセクション
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'カテゴリー',
style: Theme.of(context).textTheme.headlineSmall,
),
),
),
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 14.0),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 16.0,
crossAxisSpacing: 16.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
final categories = [
{'icon': Icons.smartphone, 'name': 'スマホ'},
{'icon': Icons.laptop, 'name': 'PC'},
{'icon': Icons.headphones, 'name': '音響機器'},
{'icon': Icons.camera_alt, 'name': 'カメラ'},
{'icon': Icons.watch, 'name': '時計'},
{'icon': Icons.sports_esports, 'name': 'ゲーム'},
{'icon': Icons.tv, 'name': 'TV'},
{'icon': Icons.kitchen, 'name': '家電'},
];
return CategoryItem(
icon: categories[index]['icon'] as IconData,
name: categories[index]['name'] as String,
);
},
childCount: 8,
),
),
),
// おすすめ商品リストセクション
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'おすすめ商品',
style: Theme.of(context).textTheme.headlineSmall,
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ProductListItem(
title: '商品名 ${index + 1}',
price: '¥${(index + 1) * 1000}',
imageUrl: 'https://via.placeholder.com/150',
);
},
childCount: 10,
),
),
],
),
);
}
}
// カテゴリーアイテムウィジェット
class CategoryItem extends StatelessWidget {
final IconData icon;
final String name;
const CategoryItem({
super.key,
required this.icon,
required this.name,
});
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, size: 32, color: Colors.blue),
),
const SizedBox(height: 8),
Text(
name,
style: const TextStyle(fontSize: 12),
textAlign: TextAlign.center,
),
],
);
}
}
// 商品リストアイテムウィジェット
class ProductListItem extends StatelessWidget {
final String title;
final String price;
final String imageUrl;
const ProductListItem({
super.key,
required this.title,
required this.price,
required this.imageUrl,
});
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.image, size: 40, color: Colors.grey),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
price,
style: TextStyle(
fontSize: 14,
color: Colors.green.shade700,
fontWeight: FontWeight.bold,
),
),
],
),
),
IconButton(
icon: const Icon(Icons.favorite_border),
onPressed: () {},
),
],
),
),
);
}
}
- SliverGridでグリッド表示
- SliverListでリスト表示
- SliverGridDelegateWithFixedCrossAxisCount
を用いてGridのレイアウトを柔軟に変更可能。