{"id":324534,"date":"2021-06-08T09:00:24","date_gmt":"2021-06-08T09:00:24","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=324534"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=324534","title":{"rendered":"\u041e\u0441\u043d\u043e\u0432\u044b Flutter \u0434\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 (\u0427\u0430\u0441\u0442\u044c VII)"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438. <\/p>\n<p>\u0410 \u043a\u0430\u043a \u0436\u0435 \u0431\u0435\u0437 \u043d\u0438\u0445? \u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u044b\u043c \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>Flutter \u0438\u043c\u0435\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a. \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441 Image, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/p>\n<p>\u041d\u0443 \u0447\u0442\u043e \u0436 \u043f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u0430\u0448 \u043f\u043b\u0430\u043d<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560008\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1<\/a>&nbsp;&#8212; \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u043f\u0435\u0440\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u043e\u043d\u044f\u0442\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560282\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 2<\/a>&nbsp;&#8212; \u0444\u0430\u0439\u043b pubspec.yaml \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 flutter \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560646\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 3<\/a>&nbsp;&#8212; BottomNavigationBar \u0438 Navigator;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560806\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 4&nbsp;<\/a>&#8212; MVC. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e\u0442 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560964\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 5<\/a>&nbsp;&#8212; http \u043f\u0430\u043a\u0435\u0442. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Repository \u043a\u043b\u0430\u0441\u0441\u0430, \u043f\u0435\u0440\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0432\u044b\u0432\u043e\u0434 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u0441\u0442\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 6 (\u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f) &#8212; \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0444\u043e\u0440\u043c\u0430\u043c\u0438, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 7 &#8212; \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u043c\u0438, \u0432\u044b\u0432\u043e\u0434 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u0432 \u0432\u0438\u0434\u0435 \u0441\u0435\u0442\u043a\u0438, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u0438\u0437 \u0441\u0435\u0442\u0438, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0438\u0445 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435;<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 8 &#8212; \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0439 \u0442\u0435\u043c\u044b, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0448\u0440\u0438\u0444\u0442\u043e\u0432 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 9 &#8212; \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438;<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a  \u0432 \u043f\u0440\u043e\u0435\u043a\u0442<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442. <\/p>\n<p>\u0411\u0443\u0434\u044c\u0442\u0435 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u0435\u0435: \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0432 \u0432\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u044e\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0443\u0441\u0435\u0440\u0434\u0441\u0442\u0432\u0443\u0439\u0442\u0435!<\/p>\n<p>\u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>images<\/code> \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ddb\/522\/834\/ddb5228346f2759d2d632b52a23886ec.png\" width=\"1138\" height=\"593\"><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>images<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 pubspec.yaml:<\/p>\n<pre><code class=\"xml\"># \u0431\u043b\u043e\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 dependencies:   flutter:     sdk: flutter    # ...  # \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 dev_dependencies: \t \t# ...  # \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0435\u043a\u0446\u0438\u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0448\u0440\u0438\u0444\u0442\u044b \u0438 assets \u0444\u0430\u0439\u043b\u044b flutter:    # \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c MaterialApp \u0438\u043a\u043e\u043d\u043a\u0438 \u0438 \u043d\u0430\u0448\u0435   # \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 Material Design   uses-material-design: true    # \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e images   # \/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c   # \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 images   assets:     - images\/<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0430\u0440\u043e\u0447\u043a\u0443 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u0438 \u0432\u0437\u044f\u0442\u044c \u0438\u0445 <a href=\"https:\/\/github.com\/KiberneticWorm\/json_placeholder_app\/tree\/lesson_7_images\/images\" rel=\"noopener noreferrer nofollow\">\u0438\u0437 Github&#8217;\u0430<\/a>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/332\/670\/420\/3326704204b0157ed92e6d38e72075f7.png\" width=\"1118\" height=\"593\"><figcaption><\/figcaption><\/figure>\n<p>\u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0443 \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <code>AlbumListPage<\/code>:<\/p>\n<pre><code class=\"dart\"> import 'package:flutter\/material.dart'; import 'package:flutter_staggered_grid_view\/flutter_staggered_grid_view.dart';  class AlbumListPage extends StatefulWidget {   @override   _AlbumListPageState createState() =&gt; _AlbumListPageState(); } class _AlbumListPageState extends State&lt;AlbumListPage&gt; {   \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0430\u0448\u0438\u0445 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439   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()     );   }      \/\/ \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u0435\u0442\u043a\u0443 \u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439   Widget _buildContent() {     \/\/ \u0440\u0430\u043d\u0435\u0435 \u043c\u044b \u0443\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u043b\u0438 \u043f\u0430\u043a\u0435\u0442 flutter_staggered_grid_view     \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 StaggeredGridView     return StaggeredGridView.countBuilder(       \/\/ \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439       itemCount: fileImages.length,       \/\/ crossAxisCount \u0437\u0430\u0434\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043e\u043d\u043e\u043a       \/\/ \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0440\u0430\u0432\u043d\u0435\u043d\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f       crossAxisCount: 8,       \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438       mainAxisSpacing: 10,       \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438       crossAxisSpacing: 10,       staggeredTileBuilder: (index) {         \/\/ \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 4 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0432 \u0448\u0438\u0440\u0438\u043d\u0443 (\u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)         \/\/ \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0447\u0435\u0442\u043d\u044b\u0445 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0445 \u0431\u0443\u0434\u0443\u0442 \u0432 2 \u0440\u0430\u0437\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 (\u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)         return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);       },       \/\/ \u0441\u0442\u0440\u043e\u0438\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435       itemBuilder: (context, index) {         return Container(           decoration: BoxDecoration(             border: Border.all(color: Colors.pinkAccent, width: 1)           ),           \/\/ Image.asset \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f           \/\/ \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0432 pubspec.yaml           \/\/ \u043f\u043e\u043c\u0438\u043c\u043e asset \u043a\u043b\u0430\u0441\u0441 Image \u0438\u043c\u0435\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b           child: Image.asset(\"images\/${fileImages[index]}\"),         );       }, );    } }<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e5f\/bbc\/9aa\/e5fbbc9aa0ab90d19f24d6ae26f21f1e.png\" width=\"1080\" height=\"2400\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0443\u0430\u043b\u044f! \u041f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u0431\u0430\u0432\u043d\u043e.<\/p>\n<h2>\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438\u0437 \u0441\u0435\u0442\u0438<\/h2>\n<p>\u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f REST API \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a.<\/p>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u044b \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438, \u0447\u0442\u043e \u043d\u0430\u0448\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>AlbumListPage. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u043b\u044c\u0431\u043e\u043c\u043e\u0432, \u0430 \u043f\u043e\u0442\u043e\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438, \u0437\u0430\u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0439 \u0434\u043b\u044f \u0432\u0430\u0441.<\/code><\/p>\n<p>\u041c\u044b \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0432\u0441\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c <code>Photo<\/code>:<\/p>\n<pre><code class=\"dart\">\/\/ \u0434\u0430\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435 Post class Photo {   final int _id;   final String _title;   final String _url;      Photo.fromJson(Map&lt;String, dynamic&gt; json) :       _id = json[\"id\"],       _title = json[\"title\"],       _url = json[\"url\"]; }  class PhotoList {   final List&lt;Photo&gt; photos = [];      PhotoList.fromJson(List&lt;dynamic&gt; jsonItems) {     for (var jsonItem in jsonItems) {       photos.add(Photo.fromJson(jsonItem));     }   }    }  abstract class PhotoResult {}  class PhotoResultSuccess extends PhotoResult {   final PhotoList photoList;   PhotoResultSuccess(this.photoList); }  \/\/ \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 class PhotoResultFailure extends PhotoResult {   final String error;   PhotoResultFailure(this.error); }  \/\/ \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 class PhotoResultLoading extends PhotoResult {   PhotoResultLoading(); }<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432 <code>Repository<\/code>:<\/p>\n<pre><code class=\"dart\">Future&lt;PhotoList&gt; fetchPhotos() async {   \/\/ \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u043c URL, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443   \/\/ \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441   final url = Uri.parse(\"$SERVER\/photos\");   \/\/ \u0434\u0435\u043b\u0430\u0435\u043c GET \u0437\u0430\u043f\u0440\u043e\u0441   final response = await http.get(url);    \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430   if (response.statusCode == 200) {     \/\/ \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u043a \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u0441\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438     \/\/ json.decode \u043f\u0430\u0440\u0441\u0438\u0442 \u043e\u0442\u0432\u0435\u0442     return PhotoList.fromJson(json.decode(response.body));   } else {     \/\/ \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435     throw Exception(\"failed request\");   } }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 <code>AlbumController<\/code>:<\/p>\n<pre><code class=\"dart\">\/\/ AlbumController \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0434 \u043d\u0430 PostController class AlbumController extends ControllerMVC {   final Repository repo = Repository();      \/\/ \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435   PhotoResult currentState = PhotoResultLoading();      void init() async {     try {       \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a       final photoList = await repo.fetchPhotos();       \/\/ \u0443\u0441\u043f\u0435\u0448\u043d\u043e       setState(() =&gt; currentState = PhotoResultSuccess(photoList));     } catch (error) {       \/\/ \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430       setState(() =&gt; currentState = PhotoResultFailure(\"\u041d\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430\"));     }   }    }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 <code>AlbumListPage<\/code>:<\/p>\n<pre><code class=\"dart\">class AlbumListPage extends StatefulWidget {   @override   _AlbumListPageState createState() =&gt; _AlbumListPageState(); }  class _AlbumListPageState extends StateMVC {    \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   \/\/ late \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e   late AlbumController _controller;    _AlbumListPageState() : super(AlbumController()){     _controller = controller as AlbumController;   }    @override   void initState() {     super.initState();     \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438\u0437 JSONPlaceholder     _controller.init();   }     @override   Widget build(BuildContext context) {     return Scaffold(         appBar: AppBar(           title: Text(\"Album List Page\"),         ),         body: _buildContent()     );   }    Widget _buildContent() {     \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f     final state = _controller.currentState;     if (state is PhotoResultLoading) {       \/\/ \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430       return Center(         child: CircularProgressIndicator(),       );     } else if (state is PhotoResultFailure) {       \/\/ \u043e\u0448\u0438\u0431\u043a\u0430       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;       \/\/ \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c StaggeredGridView \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f       \/\/ \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u0441\u0435\u0442\u043a\u0438 \u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439       return StaggeredGridView.countBuilder(         \/\/ \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439         itemCount: images.length,         \/\/ crossAxisCount \u0437\u0430\u0434\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043e\u043d\u043e\u043a         \/\/ \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0440\u0430\u0432\u043d\u0435\u043d\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f         crossAxisCount: 8,         \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438         mainAxisSpacing: 10,         \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438         crossAxisSpacing: 10,         staggeredTileBuilder: (index) {           \/\/ \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432 \u0448\u0438\u0440\u0438\u043d\u0443 4 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 (\u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)           \/\/ \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0447\u0435\u0442\u043d\u044b\u0445 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0445 \u0431\u0443\u0434\u0443\u0442 \u0432 2 \u0440\u0430\u0437\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 (\u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)           return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);         },         \/\/ \u0441\u0442\u0440\u043e\u0438\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435         itemBuilder: (context, index) {           return Container(             decoration: BoxDecoration(                 border: Border.all(color: Colors.pinkAccent, width: 1)             ),             \/\/ \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 Image.network \u0434\u043b\u044f             \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u0438\u0437 \u0441\u0435\u0442\u0438             child:  Image.network(               images[index].url,               \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443 \u0438 \u0432\u044b\u0441\u043e\u0442\u0443               width: double.infinity,               height: double.infinity,               \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f               fit: BoxFit.cover,               \/\/ \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f                \/\/ \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0442\u0435\u043a\u0441\u0442 Loading...               loadingBuilder: (context, widget, imageChunkEvent) {                 if (imageChunkEvent == null) {                   return widget;                 }                 return Center(child: Text(\"Loading...\"));               },               \/\/ \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043a\u0438                \/\/ \u0432\u043c\u0435\u0441\u0442\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 Error!               errorBuilder: (context, obj, stacktrace) =&gt; Center(child: Text(\"Error!\")),             ),           );         },        );     }   } }<\/code><\/pre>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9a3\/b51\/486\/9a3b51486c7cf2194e4bd173bd2c72c4.png\" width=\"1080\" height=\"2400\"><figcaption><\/figcaption><\/figure>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442! <\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0449\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u0435\u0442 Flutter \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u043c\u0438. <\/p>\n<p><code>Image.network <\/code>\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0430\u043d\u0430\u0446\u0435\u0435\u0439 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0431\u043e\u0435\u0432\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e.<\/p>\n<p>\u041a \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0442\u0430\u043a\u0438\u0445 \u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f <a href=\"https:\/\/pub.dev\/packages\/cached_network_image\" rel=\"noopener noreferrer nofollow\">cached_network_image<\/a><\/p>\n<p>\u042d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0431\u0438\u0431\u043b\u043e\u0442\u0435\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0435\u0440\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0432\u0441\u0435 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438.  <\/p>\n<p>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/KiberneticWorm\/json_placeholder_app\/tree\/lesson_7_images\" rel=\"noopener noreferrer nofollow\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Github<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/Image-class.html\" rel=\"noopener noreferrer nofollow\">Image class<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/flutter.dev\/docs\/development\/ui\/assets-and-images\" rel=\"noopener noreferrer nofollow\">Adding assets and images<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0441\u0435\u043c \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430!<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/561614\/\"> https:\/\/habr.com\/ru\/post\/561614\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438. <\/p>\n<p>\u0410 \u043a\u0430\u043a \u0436\u0435 \u0431\u0435\u0437 \u043d\u0438\u0445? \u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u044b\u043c \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>Flutter \u0438\u043c\u0435\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a. \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441 Image, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/p>\n<p>\u041d\u0443 \u0447\u0442\u043e \u0436 \u043f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u0430\u0448 \u043f\u043b\u0430\u043d<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560008\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1<\/a>&nbsp;&#8212; \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u043f\u0435\u0440\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u043e\u043d\u044f\u0442\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560282\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 2<\/a>&nbsp;&#8212; \u0444\u0430\u0439\u043b pubspec.yaml \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 flutter \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560646\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 3<\/a>&nbsp;&#8212; BottomNavigationBar \u0438 Navigator;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560806\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 4&nbsp;<\/a>&#8212; MVC. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e\u0442 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/post\/560964\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 5<\/a>&nbsp;&#8212; http \u043f\u0430\u043a\u0435\u0442. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Repository \u043a\u043b\u0430\u0441\u0441\u0430, \u043f\u0435\u0440\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0432\u044b\u0432\u043e\u0434 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u0441\u0442\u043e\u0432;<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 6 (\u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f) &#8212; \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0444\u043e\u0440\u043c\u0430\u043c\u0438, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 7 &#8212; \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u043c\u0438, \u0432\u044b\u0432\u043e\u0434 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u0432 \u0432\u0438\u0434\u0435 \u0441\u0435\u0442\u043a\u0438, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u0438\u0437 \u0441\u0435\u0442\u0438, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0438\u0445 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435;<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 8 &#8212; \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0439 \u0442\u0435\u043c\u044b, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0448\u0440\u0438\u0444\u0442\u043e\u0432 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 9 &#8212; \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438;<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a  \u0432 \u043f\u0440\u043e\u0435\u043a\u0442<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442. <\/p>\n<p>\u0411\u0443\u0434\u044c\u0442\u0435 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u0435\u0435: \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0432 \u0432\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u044e\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0443\u0441\u0435\u0440\u0434\u0441\u0442\u0432\u0443\u0439\u0442\u0435!<\/p>\n<p>\u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>images<\/code> \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>images<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 pubspec.yaml:<\/p>\n<pre><code class=\"xml\"># \u0431\u043b\u043e\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 dependencies:   flutter:     sdk: flutter    # ...  # \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 dev_dependencies: \t \t# ...  # \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0435\u043a\u0446\u0438\u0438 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0448\u0440\u0438\u0444\u0442\u044b \u0438 assets \u0444\u0430\u0439\u043b\u044b flutter:    # \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c MaterialApp \u0438\u043a\u043e\u043d\u043a\u0438 \u0438 \u043d\u0430\u0448\u0435   # \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 Material Design   uses-material-design: true    # \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e images   # \/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c   # \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 images   assets:     - images\/<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0430\u0440\u043e\u0447\u043a\u0443 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u0438 \u0432\u0437\u044f\u0442\u044c \u0438\u0445 <a href=\"https:\/\/github.com\/KiberneticWorm\/json_placeholder_app\/tree\/lesson_7_images\/images\" rel=\"noopener noreferrer nofollow\">\u0438\u0437 Github&#8217;\u0430<\/a>:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0443 \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <code>AlbumListPage<\/code>:<\/p>\n<pre><code class=\"dart\"> import 'package:flutter\/material.dart'; import 'package:flutter_staggered_grid_view\/flutter_staggered_grid_view.dart';  class AlbumListPage extends StatefulWidget {   @override   _AlbumListPageState createState() =&gt; _AlbumListPageState(); } class _AlbumListPageState extends State&lt;AlbumListPage&gt; {   \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0430\u0448\u0438\u0445 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439   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()     );   }      \/\/ \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u0435\u0442\u043a\u0443 \u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439   Widget _buildContent() {     \/\/ \u0440\u0430\u043d\u0435\u0435 \u043c\u044b \u0443\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u043b\u0438 \u043f\u0430\u043a\u0435\u0442 flutter_staggered_grid_view     \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 StaggeredGridView     return StaggeredGridView.countBuilder(       \/\/ \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439       itemCount: fileImages.length,       \/\/ crossAxisCount \u0437\u0430\u0434\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043e\u043d\u043e\u043a       \/\/ \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0440\u0430\u0432\u043d\u0435\u043d\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f       crossAxisCount: 8,       \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438       mainAxisSpacing: 10,       \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438       crossAxisSpacing: 10,       staggeredTileBuilder: (index) {         \/\/ \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 4 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0432 \u0448\u0438\u0440\u0438\u043d\u0443 (\u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)         \/\/ \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0447\u0435\u0442\u043d\u044b\u0445 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0445 \u0431\u0443\u0434\u0443\u0442 \u0432 2 \u0440\u0430\u0437\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 (\u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)         return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);       },       \/\/ \u0441\u0442\u0440\u043e\u0438\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435       itemBuilder: (context, index) {         return Container(           decoration: BoxDecoration(             border: Border.all(color: Colors.pinkAccent, width: 1)           ),           \/\/ Image.asset \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f           \/\/ \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0432 pubspec.yaml           \/\/ \u043f\u043e\u043c\u0438\u043c\u043e asset \u043a\u043b\u0430\u0441\u0441 Image \u0438\u043c\u0435\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b           child: Image.asset(\"images\/${fileImages[index]}\"),         );       }, );    } }<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0443\u0430\u043b\u044f! \u041f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u0431\u0430\u0432\u043d\u043e.<\/p>\n<h2>\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438\u0437 \u0441\u0435\u0442\u0438<\/h2>\n<p>\u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f REST API \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a.<\/p>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u044b \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438, \u0447\u0442\u043e \u043d\u0430\u0448\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>AlbumListPage. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u043b\u044c\u0431\u043e\u043c\u043e\u0432, \u0430 \u043f\u043e\u0442\u043e\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438, \u0437\u0430\u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0439 \u0434\u043b\u044f \u0432\u0430\u0441.<\/code><\/p>\n<p>\u041c\u044b \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0432\u0441\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c <code>Photo<\/code>:<\/p>\n<pre><code class=\"dart\">\/\/ \u0434\u0430\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435 Post class Photo {   final int _id;   final String _title;   final String _url;      Photo.fromJson(Map&lt;String, dynamic&gt; json) :       _id = json[\"id\"],       _title = json[\"title\"],       _url = json[\"url\"]; }  class PhotoList {   final List&lt;Photo&gt; photos = [];      PhotoList.fromJson(List&lt;dynamic&gt; jsonItems) {     for (var jsonItem in jsonItems) {       photos.add(Photo.fromJson(jsonItem));     }   }    }  abstract class PhotoResult {}  class PhotoResultSuccess extends PhotoResult {   final PhotoList photoList;   PhotoResultSuccess(this.photoList); }  \/\/ \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 class PhotoResultFailure extends PhotoResult {   final String error;   PhotoResultFailure(this.error); }  \/\/ \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 class PhotoResultLoading extends PhotoResult {   PhotoResultLoading(); }<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432 <code>Repository<\/code>:<\/p>\n<pre><code class=\"dart\">Future&lt;PhotoList&gt; fetchPhotos() async {   \/\/ \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u043c URL, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443   \/\/ \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441   final url = Uri.parse(\"$SERVER\/photos\");   \/\/ \u0434\u0435\u043b\u0430\u0435\u043c GET \u0437\u0430\u043f\u0440\u043e\u0441   final response = await http.get(url);    \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430   if (response.statusCode == 200) {     \/\/ \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u043a \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u0441\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438     \/\/ json.decode \u043f\u0430\u0440\u0441\u0438\u0442 \u043e\u0442\u0432\u0435\u0442     return PhotoList.fromJson(json.decode(response.body));   } else {     \/\/ \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435     throw Exception(\"failed request\");   } }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 <code>AlbumController<\/code>:<\/p>\n<pre><code class=\"dart\">\/\/ AlbumController \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0434 \u043d\u0430 PostController class AlbumController extends ControllerMVC {   final Repository repo = Repository();      \/\/ \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435   PhotoResult currentState = PhotoResultLoading();      void init() async {     try {       \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a       final photoList = await repo.fetchPhotos();       \/\/ \u0443\u0441\u043f\u0435\u0448\u043d\u043e       setState(() =&gt; currentState = PhotoResultSuccess(photoList));     } catch (error) {       \/\/ \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430       setState(() =&gt; currentState = PhotoResultFailure(\"\u041d\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430\"));     }   }    }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 <code>AlbumListPage<\/code>:<\/p>\n<pre><code class=\"dart\">class AlbumListPage extends StatefulWidget {   @override   _AlbumListPageState createState() =&gt; _AlbumListPageState(); }  class _AlbumListPageState extends StateMVC {    \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   \/\/ late \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e   late AlbumController _controller;    _AlbumListPageState() : super(AlbumController()){     _controller = controller as AlbumController;   }    @override   void initState() {     super.initState();     \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438\u0437 JSONPlaceholder     _controller.init();   }     @override   Widget build(BuildContext context) {     return Scaffold(         appBar: AppBar(           title: Text(\"Album List Page\"),         ),         body: _buildContent()     );   }    Widget _buildContent() {     \/\/ \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f     final state = _controller.currentState;     if (state is PhotoResultLoading) {       \/\/ \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430       return Center(         child: CircularProgressIndicator(),       );     } else if (state is PhotoResultFailure) {       \/\/ \u043e\u0448\u0438\u0431\u043a\u0430       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;       \/\/ \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c StaggeredGridView \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f       \/\/ \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u0441\u0435\u0442\u043a\u0438 \u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439       return StaggeredGridView.countBuilder(         \/\/ \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439         itemCount: images.length,         \/\/ crossAxisCount \u0437\u0430\u0434\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043e\u043d\u043e\u043a         \/\/ \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0440\u0430\u0432\u043d\u0435\u043d\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f         crossAxisCount: 8,         \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438         mainAxisSpacing: 10,         \/\/ \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438         crossAxisSpacing: 10,         staggeredTileBuilder: (index) {           \/\/ \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432 \u0448\u0438\u0440\u0438\u043d\u0443 4 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 (\u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)           \/\/ \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0447\u0435\u0442\u043d\u044b\u0445 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0445 \u0431\u0443\u0434\u0443\u0442 \u0432 2 \u0440\u0430\u0437\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 (\u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)           return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);         },         \/\/ \u0441\u0442\u0440\u043e\u0438\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435         itemBuilder: (context, index) {           return Container(             decoration: BoxDecoration(                 border: Border.all(color: Colors.pinkAccent, width: 1)             ),             \/\/ \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 Image.network \u0434\u043b\u044f             \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a \u0438\u0437 \u0441\u0435\u0442\u0438             child:  Image.network(               images[index].url,               \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443 \u0438 \u0432\u044b\u0441\u043e\u0442\u0443               width: double.infinity,               height: double.infinity,               \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f               fit: BoxFit.cover,               \/\/ \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f                \/\/ \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0442\u0435\u043a\u0441\u0442 Loading...               loadingBuilder: (context, widget, imageChunkEvent) {                 if (imageChunkEvent == null) {                   return widget;                 }                 return Center(child: Text(\"Loading...\"));               },               \/\/ \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043a\u0438                \/\/ \u0432\u043c\u0435\u0441\u0442\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 Error!               errorBuilder: (context, obj, stacktrace) =&gt; Center(child: Text(\"Error!\")),             ),           );         },        );     }   } }<\/code><\/pre>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442! <\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0449\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u0435\u0442 Flutter \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u043c\u0438. <\/p>\n<p><code>Image.network <\/code>\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0430\u043d\u0430\u0446\u0435\u0435\u0439 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0431\u043e\u0435\u0432\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e.<\/p>\n<p>\u041a \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0442\u0430\u043a\u0438\u0445 \u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f <a href=\"https:\/\/pub.dev\/packages\/cached_network_image\" rel=\"noopener noreferrer nofollow\">cached_network_image<\/a><\/p>\n<p>\u042d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0431\u0438\u0431\u043b\u043e\u0442\u0435\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0435\u0440\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0432\u0441\u0435 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438.  <\/p>\n<p>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/KiberneticWorm\/json_placeholder_app\/tree\/lesson_7_images\" rel=\"noopener noreferrer nofollow\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Github<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/Image-class.html\" rel=\"noopener noreferrer nofollow\">Im<\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-324534","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/324534","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=324534"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/324534\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=324534"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=324534"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=324534"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}