A Flutter package that provides a collection of list-related widgets with consistent styling and behavior.

InfoList: A flexible list widget that supports:
- Generic type support for any data model
- Empty state handling with customizable UI
- Skeleton loading UI with shimmer effect
- AsyncValue integration with Riverpod
- Custom item builders
- Custom separators
- Custom styling options
InfoCard: A card widget that wraps content with consistent styling
InfoHeader: A header widget for cards with title and optional actions
InfoItemBase: A base model for list items with common properties
Add the package to your pubspec.yaml:
dependencies:
flutter_list_ui: ^1.4.2
shimmer: ^3.0.0 # Optional: for skeleton loading effect
InfoList.info(
items: items,
buildItem: (item) => ListTile(
title: Text(item.title),
subtitle: Text(item.subtitle),
),
);
InfoList.info(
items: items,
buildEmptyItem: (context, items) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.inbox_outlined,
size: 48,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'데이터가 없습니다',
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
],
),
),
buildItem: (item) => ListTile(
title: Text(item.title),
subtitle: Text(item.subtitle),
),
);
InfoList.info(
items: items,
isLoading: true,
skeletonCount: 3,
skeletonBuilder: (context, index) => Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.grey[300],
shape: BoxShape.circle,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: 20,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(height: 8),
Container(
width: 150,
height: 16,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
),
],
),
),
],
),
),
);
InfoList.when(
value: itemsAsyncValue,
buildItem: (item) => ListTile(
title: Text(item.title),
subtitle: Text(item.subtitle),
),
buildEmptyItem: (context, items) => Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.search_off,
size: 48,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'검색 결과가 없습니다',
style: TextStyle(
color: Colors.grey[600],
fontSize: 16,
),
),
const SizedBox(height: 8),
Text(
'다른 검색어를 시도해보세요',
style: TextStyle(
color: Colors.grey[500],
fontSize: 14,
),
),
],
),
),
);
import 'package:shimmer/shimmer.dart';
InfoList.info(
items: items,
isLoading: true,
skeletonBuilder: (context, index) => Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(height: 8),
Container(
width: 150,
height: 16,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
),
),
],
),
),
],
),
),
),
);
Info(
card: InfoCard(
header: InfoHeader(
title: 'List Title',
titleStyle: Theme.of(context).textTheme.titleLarge,
),
body: InfoList.info(
items: items,
buildItem: (item) => ListTile(
title: Text(item.title),
subtitle: Text(item.subtitle),
),
),
backgroundColor: Colors.white,
isRound: true,
showBorder: false,
),
);
| Property |
Type |
Description |
| card |
InfoCard |
The InfoCard widget to display |
| paddingOption |
String |
Padding option ('all' or 'symmetric', default: 'all') |
| paddingVertical |
double |
Vertical padding value (default: 8.0) |
| paddingHorizontal |
double |
Horizontal padding value (default: 8.0) |
| Property |
Type |
Description |
| header |
InfoHeaderBase |
Header widget |
| body |
InfoList |
Main content widget |
| isRound |
bool |
Whether to show rounded corners (default: false) |
| backgroundColor |
Color? |
Background color |
| margin |
EdgeInsetsGeometry? |
Margin around the card |
| padding |
EdgeInsetsGeometry? |
Padding around the content |
| showBorder |
bool |
Whether to show border (default: true) |
| borderColor |
Color? |
Border color |
| useSliver |
bool |
Whether to use SliverList (default: false) |
| Property |
Type |
Description |
| title |
String |
Title text |
| subtitle |
String? |
Optional subtitle text |
| trailing |
Widget? |
Optional trailing widget |
| titleStyle |
TextStyle? |
Style for the title text |
| subtitleStyle |
TextStyle? |
Style for the subtitle text |
| backgroundColor |
Color? |
Background color |
| padding |
EdgeInsetsGeometry? |
Padding around the content |
| Property |
Type |
Description |
| items |
List |
List of items to display |
| buildItem |
Widget Function(T) |
Function to build each item |
| backgroundColor |
Color? |
Background color |
| contentPadding |
EdgeInsetsGeometry? |
Padding around the list content |
| shrinkWrap |
bool |
Whether the list should shrink-wrap its content (default: true) |
| separatorBuilder |
Widget Function(BuildContext, int)? |
Function to build separator widgets |
| physics |
ScrollPhysics? |
Scroll physics for the list |
| itemPadding |
EdgeInsetsGeometry? |
Padding for each item |
| itemDecoration |
BoxDecoration? |
Decoration for each item container |
| removeTopPadding |
bool |
Whether to remove top padding (default: false) |
| emptyWidget |
Widget? |
Widget to show when items is empty |
| isLoading |
bool |
Whether to show skeleton loading UI (default: false) |
| skeletonCount |
int |
Number of skeleton items to show (default: 3) |
| skeletonBuilder |
Widget Function(BuildContext, int)? |
Function to build skeleton items |
| buildEmptyItem |
Widget Function(BuildContext, List |
Function to build empty state UI |
| useSliver |
bool |
Whether to use SliverList (default: false) |
| Property |
Type |
Description |
| header |
InfoHeaderBase |
Header widget |
| body |
InfoList |
Main content widget |
| isRound |
bool |
Whether to show rounded corners (default: false) |
| backgroundColor |
Color? |
Background color |
| margin |
EdgeInsetsGeometry? |
Margin around the card |
| padding |
EdgeInsetsGeometry? |
Padding around the content |
| builder |
Widget Function(BuildContext, WidgetRef)? |
Custom builder function |
| showBorder |
bool |
Whether to show border (default: true) |
| borderColor |
Color? |
Border color |
| useSliver |
bool |
Whether to use SliverList (default: false) |
| Property |
Type |
Description |
| items |
List |
List of items to display |
| buildItem |
Widget Function(T) |
Function to build each item |
| backgroundColor |
Color? |
Background color |
| contentPadding |
EdgeInsetsGeometry? |
Padding around the list content |
| shrinkWrap |
bool |
Whether the list should shrink-wrap its content (default: true) |
| separatorBuilder |
Widget Function(BuildContext, int)? |
Function to build separator widgets |
| physics |
ScrollPhysics? |
Scroll physics for the list |
| itemPadding |
EdgeInsetsGeometry? |
Padding for each item |
| itemDecoration |
BoxDecoration? |
Decoration for each item container |
| removeTopPadding |
bool |
Whether to remove top padding (default: false) |
| emptyWidget |
Widget? |
Widget to show when items is empty |
| isLoading |
bool |
Whether to show skeleton loading UI (default: false) |
| skeletonCount |
int |
Number of skeleton items to show (default: 3) |
| skeletonBuilder |
Widget Function(BuildContext, int)? |
Function to build skeleton items |
| buildEmptyItem |
Widget Function(BuildContext, List |
Function to build empty state UI |
| useSliver |
bool |
Whether to use SliverList (default: false) |
| Property |
Type |
Description |
| items |
List |
List of items to display |
| buildItem |
Widget Function(T) |
Function to build each item |
| backgroundColor |
Color? |
Background color |
| contentPadding |
EdgeInsetsGeometry? |
Padding around the list content |
| shrinkWrap |
bool |
Whether the list should shrink-wrap its content (default: true) |
| separatorBuilder |
Widget Function(BuildContext, int)? |
Function to build separator widgets |
| physics |
ScrollPhysics? |
Scroll physics for the list |
| itemPadding |
EdgeInsetsGeometry? |
Padding for each item |
| itemDecoration |
BoxDecoration? |
Decoration for each item container |
| removeTopPadding |
bool |
Whether to remove top padding (default: false) |
| emptyWidget |
Widget? |
Widget to show when items is empty |
| isLoading |
bool |
Whether to show skeleton loading UI (default: false) |
| skeletonCount |
int |
Number of skeleton items to show (default: 3) |
| skeletonBuilder |
Widget Function(BuildContext, int)? |
Function to build skeleton items |
| buildEmptyItem |
Widget Function(BuildContext, List |
Function to build empty state UI |
| useSliver |
bool |
Whether to use SliverList (default: false) |
| Property |
Type |
Description |
| items |
List |
List of items to display |
| buildItem |
Widget Function(T) |
Function to build each item |
| backgroundColor |
Color? |
Background color |
| contentPadding |
EdgeInsetsGeometry? |
Padding around the list content |
| shrinkWrap |
bool |
Whether the list should shrink-wrap its content (default: true) |
| separatorBuilder |
Widget Function(BuildContext, int)? |
Function to build separator widgets |
| physics |
ScrollPhysics? |
Scroll physics for the list |
| itemPadding |
EdgeInsetsGeometry? |
Padding for each item |
| itemDecoration |
BoxDecoration? |
Decoration for each item container |
| removeTopPadding |
bool |
Whether to remove top padding (default: false) |
| emptyWidget |
Widget? |
Widget to show when items is empty |
| isLoading |
bool |
Whether to show skeleton loading UI (default: false) |
| skeletonCount |
int |
Number of skeleton items to show (default: 3) |
| skeletonBuilder |
Widget Function(BuildContext, int)? |
Function to build skeleton items |
| buildEmptyItem |
Widget Function(BuildContext, List |
Function to build empty state UI |
| useSliver |
bool |
Whether to use SliverList (default: false) |
- flutter_riverpod: ^2.5.1 (Required for AsyncValue support)
- flutter_screenutil: ^5.9.0
- google_fonts: ^6.1.0
- cached_network_image: ^3.3.1
- shimmer: ^3.0.0 (Optional: for skeleton loading effect)
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
A reusable Flutter UI components package