[Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть VII)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Большинство мобильных приложений содержат различные картинки. А как же без них? Картинки делают насыщенным и более понятным пользовательский интерфейс пользователя.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
===========
Похожие новости:
- [Разработка под iOS, Разработка под MacOS] Что ждать разработчику от WWDC 2021
- [Разработка мобильных приложений, Разработка под Android, Исследования и прогнозы в IT, История IT] Долгая дорога к быстрым обновлениям Android
- [Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть VI)
- [Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть V)
- [Разработка мобильных приложений, Разработка под Android, Gradle] Проекты в Gradle 7: как не зависеть от зависимостей
- [Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть IV)
- [Разработка под Android] Всё о PendingIntents (перевод)
- [Разработка под Android, Kotlin] Proto DataStore + AndroidX Preferences на Kotlin
- [Разработка под Android] Все новинки Android 12. Обзор для разработчиков
- [Разработка под Android, Dart, Flutter] Основы Flutter для начинающих (Часть II)
Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_dart, #_flutter, #_image, #_network, #_flutter, #_dart, #_mobile_development, #_mvc, #_razrabotka_pod_android (
Разработка под Android
), #_dart, #_flutter
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:41
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Большинство мобильных приложений содержат различные картинки. А как же без них? Картинки делают насыщенным и более понятным пользовательский интерфейс пользователя.Flutter имеет встроенную поддержку картинок. Наиболее часто используемым является класс Image, который мы и рассмотрим в данной статье.Ну что ж поехали!Наш план
Затем нужно прописать директорию images в файле pubspec.yaml: # блок зависимостей
dependencies: flutter: sdk: flutter # ... # зависимости для разработки dev_dependencies: # ... # в данной секции вы можете подключить шрифты и assets файлы flutter: # указываем, что мы используем MaterialApp иконки и наше # приложение соответствует Material Design uses-material-design: true # прописываем директорию images # / указывает на то, что мы собираемся включить # все файлы которые будут в директории images assets: - images/ Отредактируем нашу пустую страницу 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(); } 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 очень поход на 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("Нет интернета")); } } } 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 =========== Похожие новости:
Разработка под Android ), #_dart, #_flutter |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:41
Часовой пояс: UTC + 5