Welcome to Day 12 of the "Hundred Days of Flutter" course! Today, we'll explore how to work with assets and resources in Flutter, which is essential for creating visually appealing applications.
flutter:
assets:
- assets/images/
- assets/icons/
- assets/data/
Image.asset(
'assets/images/logo.png',
width: 200,
height: 200,
fit: BoxFit.contain,
)
Future<void> loadJsonData() async {
final String jsonString = await rootBundle.loadString('assets/data/config.json');
final Map<String, dynamic> jsonData = json.decode(jsonString);
print(jsonData);
}
First, add the font files to your project and declare them in pubspec.yaml
:
flutter:
fonts:
- family: RobotoMono
fonts:
- asset: assets/fonts/RobotoMono-Regular.ttf
- asset: assets/fonts/RobotoMono-Bold.ttf
weight: 700
Text(
'Hello World',
style: TextStyle(
fontFamily: 'RobotoMono',
fontSize: 24,
),
)
Images
Fonts
Data Files
Other Resources
// Different resolutions for different pixel densities
Image.asset(
'assets/images/logo.png', // Will automatically use the appropriate resolution
width: 200,
height: 200,
)
Image.asset(
'assets/images/logo.png',
width: 200,
height: 200,
// Platform-specific image
image: AssetImage(
'assets/images/logo.png',
bundle: rootBundle,
),
)
Text(
'Hello World',
style: TextStyle(
fontFamily: Platform.isIOS ? 'SF Pro' : 'Roboto',
fontSize: 24,
),
)
class AssetPreloader {
static Future<void> preloadAssets() async {
await Future.wait([
precacheImage(AssetImage('assets/images/logo.png'), context),
rootBundle.load('assets/data/config.json'),
]);
}
}
class SafeAssetImage extends StatelessWidget {
final String assetPath;
final double width;
final double height;
const SafeAssetImage({
super.key,
required this.assetPath,
required this.width,
required this.height,
});
@override
Widget build(BuildContext context) {
return Image.asset(
assetPath,
width: width,
height: height,
errorBuilder: (context, error, stackTrace) {
return Container(
width: width,
height: height,
color: Colors.grey[300],
child: Center(
child: Icon(Icons.error),
),
);
},
);
}
}
Let's test your understanding of today's concepts:
What is the purpose of the assets section in pubspec.yaml?
Which file format is commonly used for custom fonts in Flutter?
What is the purpose of asset bundling in Flutter?
Create an app that:
Here's a starting point:
class AssetManagementApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
fontFamily: 'RobotoMono',
),
home: AssetManagementScreen(),
);
}
}
class AssetManagementScreen extends StatefulWidget {
@override
_AssetManagementScreenState createState() => _AssetManagementScreenState();
}
class _AssetManagementScreenState extends State<AssetManagementScreen> {
bool _isLoading = true;
Map<String, dynamic>? _configData;
String? _error;
@override
void initState() {
super.initState();
_loadAssets();
}
Future<void> _loadAssets() async {
try {
// Preload assets
await Future.wait([
precacheImage(AssetImage('assets/images/logo.png'), context),
rootBundle.load('assets/data/config.json'),
]);
// Load JSON data
final String jsonString = await rootBundle.loadString('assets/data/config.json');
final Map<String, dynamic> jsonData = json.decode(jsonString);
setState(() {
_configData = jsonData;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Asset Management'),
centerTitle: true,
),
body: _isLoading
? Center(child: CircularProgressIndicator())
: _error != null
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, color: Colors.red, size: 48),
SizedBox(height: 16),
Text(
'Error loading assets',
style: TextStyle(
fontFamily: 'RobotoMono',
fontSize: 18,
),
),
SizedBox(height: 8),
Text(
_error!,
style: TextStyle(
fontFamily: 'RobotoMono',
color: Colors.red,
),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: _loadAssets,
child: Text('Retry'),
),
],
),
)
: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SafeAssetImage(
assetPath: 'assets/images/logo.png',
width: 200,
height: 200,
),
SizedBox(height: 24),
Text(
'Configuration Data:',
style: TextStyle(
fontFamily: 'RobotoMono',
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
json.encode(_configData),
style: TextStyle(
fontFamily: 'RobotoMono',
fontSize: 16,
),
),
],
),
),
);
}
}
Tomorrow, we'll explore styling and theming in Flutter!
Learn how to create and handle forms in Flutter, including form validation, different input types, and best practices for user interaction.
Start Previous DayMaster Flutter's theming system, including ThemeData, colors, typography, custom themes, dark mode, and responsive design basics.
Start Next Day