[Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть VII)

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
08-Июн-2021 13:34

Большинство мобильных приложений содержат различные картинки. А как же без них? Картинки делают насыщенным и более понятным пользовательский интерфейс пользователя.Flutter имеет встроенную поддержку картинок. Наиболее часто используемым является класс Image, который мы и рассмотрим в данной статье.Ну что ж поехали!Наш план
  • Часть 1 - введение в разработку, первое приложение, понятие состояния;
  • Часть 2 - файл pubspec.yaml и использование flutter в командной строке;
  • Часть 3 - BottomNavigationBar и Navigator;
  • Часть 4 - MVC. Мы будем использовать именно этот паттерн, как один из самых простых;
  • Часть 5 - http пакет. Создание Repository класса, первые запросы, вывод списка постов;
  • Часть 6 (текущая статья) - работа с формами, текстовые поля и создание поста.
  • Часть 7 - работа с картинками, вывод картинок в виде сетки, получение картинок из сети, добавление своих в приложение;
  • Часть 8 - создание своей темы, добавление кастомных шрифтов и анимации;
  • Часть 9 - немного о тестировании;
Добавление картинок в проектДля начала попробуем добавить собственные картинки в проект. Будьте осторожнее: картинки добавленные в ваш проект увеличивают размер приложения, так что не переусердствуйте!Для добавления картинок нам нужно создать новую директорию images в корне проекта:
Затем нужно прописать директорию 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 не является панацеей и поэтому в боевых проектах лучше использовать специальные библиотеки с большей функциональностью.К одной из таких перспективных библиотек относится cached_network_imageЭто довольно простая библотека, которая берет на себя все технические моменты и сложности. Полезные ссылки: Всем хорошего кода!
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_dart, #_flutter, #_image, #_network, #_flutter, #_dart, #_mobile_development, #_mvc, #_razrabotka_pod_android (
Разработка под Android
)
, #_dart, #_flutter
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 12-Май 21:03
Часовой пояс: UTC + 5