Most mobile applications contain various pictures.
But what about without them? Pictures make the user interface richer and clearer.
Flutter has built-in support for images. The most commonly used class is the Image class, which we will look at in this article.
Well let's go!
Our plan
Part 1 - introduction to development, first appendix, concept of state;
Part 2 - pubspec.yaml file and using flutter on the command line;
Part 3 - BottomNavigationBar and Navigator;
Part 4 - MVC. We will use this particular pattern as one of the simplest;
Part 5 - http package. Creation of the Repository class, first requests, listing of posts;
Part 6 - working with forms, text fields and creating a post.
Part 7 (current article) - working with pictures, displaying pictures in the form of a grid, receiving pictures from the network, adding your own to the application;
Part 8 - creating your own theme, adding custom fonts and animations;
Part 9 - a little about testing;
Adding pictures to the project
First, let's try to add our own pictures to the project.
Be careful: images added to your project increase the size of the application, so don't overdo it!
To add pictures, we need to create a new directory images
at the root of the project:
images
pubspec.yaml:
# dependencies: flutter: sdk: flutter # ... # dev_dependencies: # ... # assets flutter: # , MaterialApp # Material Design uses-material-design: true # images # / , # images assets: - images/
. Github':
AlbumListPage
:
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
class AlbumListPage extends StatefulWidget {
@override
_AlbumListPageState createState() => _AlbumListPageState();
}
class _AlbumListPageState extends State<AlbumListPage> {
//
final fileImages = [
"applejack.png",
"fluttershy.png",
"rarity.png",
"starlight_glimmer.png",
"twillight_sparkle.png"
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Album List Page"),
),
body: _buildContent()
);
}
//
Widget _buildContent() {
// flutter_staggered_grid_view
// StaggeredGridView
return StaggeredGridView.countBuilder(
//
itemCount: fileImages.length,
// crossAxisCount
//
crossAxisCount: 8,
//
mainAxisSpacing: 10,
//
crossAxisSpacing: 10,
staggeredTileBuilder: (index) {
// 4 ( )
// 2 ( )
return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);
},
//
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.pinkAccent, width: 1)
),
// Image.asset
// pubspec.yaml
// asset Image
child: Image.asset("images/${fileImages[index]}"),
);
},
);
}
}
.
! .
REST API .
, AlbumListPage. , , .
.
Photo
:
// Post
class Photo {
final int _id;
final String _title;
final String _url;
Photo.fromJson(Map<String, dynamic> json) :
_id = json["id"],
_title = json["title"],
_url = json["url"];
}
class PhotoList {
final List<Photo> photos = [];
PhotoList.fromJson(List<dynamic> jsonItems) {
for (var jsonItem in jsonItems) {
photos.add(Photo.fromJson(jsonItem));
}
}
}
abstract class PhotoResult {}
class PhotoResultSuccess extends PhotoResult {
final PhotoList photoList;
PhotoResultSuccess(this.photoList);
}
//
class PhotoResultFailure extends PhotoResult {
final String error;
PhotoResultFailure(this.error);
}
//
class PhotoResultLoading extends PhotoResult {
PhotoResultLoading();
}
Repository
:
Future<PhotoList> fetchPhotos() async {
// URL,
//
final url = Uri.parse("$SERVER/photos");
// GET
final response = await http.get(url);
//
if (response.statusCode == 200) {
//
// json.decode
return PhotoList.fromJson(json.decode(response.body));
} else {
//
throw Exception("failed request");
}
}
AlbumController
:
// AlbumController PostController
class AlbumController extends ControllerMVC {
final Repository repo = Repository();
//
PhotoResult currentState = PhotoResultLoading();
void init() async {
try {
//
final photoList = await repo.fetchPhotos();
//
setState(() => currentState = PhotoResultSuccess(photoList));
} catch (error) {
//
setState(() => currentState = PhotoResultFailure(" "));
}
}
}
AlbumListPage
:
class AlbumListPage extends StatefulWidget {
@override
_AlbumListPageState createState() => _AlbumListPageState();
}
class _AlbumListPageState extends StateMVC {
//
// late
late AlbumController _controller;
_AlbumListPageState() : super(AlbumController()){
_controller = controller as AlbumController;
}
@override
void initState() {
super.initState();
// JSONPlaceholder
_controller.init();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Album List Page"),
),
body: _buildContent()
);
}
Widget _buildContent() {
//
final state = _controller.currentState;
if (state is PhotoResultLoading) {
//
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PhotoResultFailure) {
//
return Center(
child: Text(
state.error,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4!.copyWith(color: Colors.red)
),
);
} else {
final images = (state as PhotoResultSuccess).photoList.photos;
// StaggeredGridView
//
return StaggeredGridView.countBuilder(
//
itemCount: images.length,
// crossAxisCount
//
crossAxisCount: 8,
//
mainAxisSpacing: 10,
//
crossAxisSpacing: 10,
staggeredTileBuilder: (index) {
// 4 ( )
// 2 ( )
return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);
},
//
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.pinkAccent, width: 1)
),
// Image.network
//
child: Image.network(
images[index].url,
//
width: double.infinity,
height: double.infinity,
//
fit: BoxFit.cover,
//
// Loading...
loadingBuilder: (context, widget, imageChunkEvent) {
if (imageChunkEvent == null) {
return widget;
}
return Center(child: Text("Loading..."));
},
//
// Error!
errorBuilder: (context, obj, stacktrace) => Center(child: Text("Error!")),
),
);
},
);
}
}
}
.
!
, Flutter .
Image.network
is not a panacea and therefore it is better to use special libraries with more functionality in combat projects.
One of these promising libraries is cached_network_image
This is a fairly simple library that takes care of all the technical issues and complexities.
Useful links:
Good code everyone!