Flutter для iOS — добавление элемента
Каждый год мы пытаемся улучшить наш рождественский ужин, в этом году основное внимание уделяется лучшему жаркому.
Давайте посмотрим, как мы можем найти и добавить новый рецепт жареного картофеля в наш дайджест.
Принятие этого требования должно быть в состоянии:
- Поиск нового рецепта
- Сохраните в наш дайджест:
- Заголовок
- Автор
- Миниатюрное изображение
Для начала я добавил верхнюю панель навигации с действием, которое позволяет нам добавить рецепт.
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
heroTag: "RecipeTabHeroTag",
transitionBetweenRoutes: false,
middle: Text(
"Recipies",
),
trailing: Icon(CupertinoIcons.add)
),
child: Container(
color: CupertinoColors.activeGreen,
child: recipiesList(),
),
);
}
Я переименовал вкладку обратно в «Дайджесты», теперь у нас есть заголовок «Рецепты» в верхней панели навигации.
Теперь для другого быстрого решения мы собираемся скользить вверх по экрану, когда нажимается кнопка добавления, и показывать панель поиска, чтобы мы могли найти новые рецепты.
Таким образом, нам просто нужно использовать поиск Google, чтобы найти несколько новых рецептов.
За этим я обратился в SerpAPI и взял некоторые данные из поиска рецептов жареной картошки с бальзамическим уксусом.
https://serpapi.com/search.json?q=Roast+potatoes+with+balsamic&location=United+Kingdom&hl=en&gl=uk&google_domain=google.co.uk&api_key=secret_api_key
{
"search_metadata": {
"id": "61c3369cc99903747c1e643b",
"status": "Success",
"json_endpoint": "https://serpapi.com/searches/bdb5db8a7f4c5593/61c3369cc99903747c1e643b.json",
"created_at": "2021-12-22 14:30:52 UTC",
"processed_at": "2021-12-22 14:30:52 UTC",
"google_url": "https://www.google.co.uk/search?q=Roast+potatoes+with+balsamic&oq=Roast+potatoes+with+balsamic&uule=w+CAIQICIOVW5pdGVkIEtpbmdkb20&hl=en&gl=uk&sourceid=chrome&ie=UTF-8",
"raw_html_file": "https://serpapi.com/searches/bdb5db8a7f4c5593/61c3369cc99903747c1e643b.html",
"total_time_taken": 1.99
},
"search_parameters": {
"engine": "google",
"q": "Roast potatoes with balsamic",
"location_requested": "United Kingdom",
"location_used": "United Kingdom",
"google_domain": "google.co.uk",
"hl": "en",
"gl": "uk",
"device": "desktop"
},
"search_information": {
"organic_results_state": "Results for exact spelling",
"query_displayed": "Roast potatoes with balsamic",
"total_results": 12800000,
"time_taken_displayed": 0.49
},
"recipes_results": [
{
"title": "Balsamic potatoes",
"link": "https://www.jamieoliver.com/recipes/potato-recipes/balsamic-potatoes/",
"source": "Jamie Oliver",
"total_time": "2 hrs 20 mins",
"ingredients":
[
"Balsamic vinegar",
"maris piper potatoes",
"red onions",
"rocket",
"olive oil"
],
"thumbnail": "https://serpapi.com/searches/61c3369cc99903747c1e643b/images/bd928f9ef521c02bbdb2df96157011d6a02d619d06f8a6e0e62bb157f48e10e5.jpeg"
},
{
"title": "Balsamic roast potatoes",
"link": "https://www.taste.com.au/recipes/balsamic-roast-potatoes/1bcb6bd4-2efa-4f01-bc98-f2ce32eaa906",
"source": "Taste",
"rating": 4,
"reviews": 2,
"total_time": "1 hr 5 mins",
"ingredients":
[
"Balsamic vinegar",
"kipfler potatoes",
"olive oil",
"garlic"
],
"thumbnail": "https://serpapi.com/searches/61c3369cc99903747c1e643b/images/bd928f9ef521c02bbdb2df96157011d625322c9b727d95f76706f0471bbaba31.jpeg"
},
{
"title": "Balsamic roast potatoes",
"link": "https://www.delicious.com.au/recipes/balsamic-roast-potatoes/1e2f30ad-d9b4-41bf-aa2e-16f1e2accfb7",
"source": "Delicious",
"rating": 5,
"reviews": 1,
"total_time": "1 hr 5 mins",
"ingredients":
[
"Balsamic vinegar",
"kipfler potatoes",
"olive oil",
"garlic"
],
"thumbnail": "https://serpapi.com/searches/61c3369cc99903747c1e643b/images/bd928f9ef521c02bbdb2df96157011d6ebca3a2868589cb9feab32215a0ba5e8.jpeg"
}
]
}
Добавлен список для возврата результатов поиска.
Когда результат выбран (onTap), мы добавляем его в наш дайджест рецепта.
Ta Da
Задняя конфорка
Сохранение дайджеста.
Пока мы сохраняем добавленный рецепт в памяти, позже мы можем сохранить его локально и удаленно в наших хранилищах данных.
Только для iOS — нажмите вкладку для сброса
Добавление функциональности для возврата к верхнему уровню/состоянию при нажатии на элемент текущей вкладки, это хороший опыт работы с iOS, дизайн, которого ожидают люди.
Анимированная панель поиска
Я решил не внедрять более расширенную панель поиска, подобную той, что в приложении Apple «App Store», где анимация находится в фокусе.
Мы можем посмотреть на это и попытаться улучшить панель поиска позже, когда основы будут в форме.
КупертиноSearchTextField
Я получаю сообщения об ошибках на уровне библиотеки от Flutter, которые просят меня сообщить об ошибке фреймворка, когда я нажимаю ввод на клавиатуре в поле поиска с помощью эмулятора iOS.
На данный момент я абстрагировал его в виджет и намерен заменить его пользовательской версией с большим количеством функций.
Я также заметил, что вам нужно дважды нажать на клавиатуре в эмуляторе, прежде чем сработает событие «OnTap».
XP
Данные в памяти
Нам нужно хранить и поддерживать список рецептов, чтобы иметь возможность добавлять новые рецепты.
На данный момент мы используем класс репозитория памяти для управления этим и внедряем его как ChangeNotifierProvider.
ChangeNotifierProvider<MemoryRepository>(
create: (_) => MemoryRepository(),
lazy: false,
),
Звучит сложно, но это всего лишь список рецептов в памяти и несколько методов их добавления и извлечения.
List<Recipe> findAllRecipes();
Recipe addRecipe(Recipe recipe);
См. документацию Flutter для получения дополнительной информации об управлении состоянием.
Когда мы переходим в хранилище данных, например. БД через API мы можем улучшить этот код.
Повторное использование элемента списка
В рамках отображения результатов поиска нам нужно снова отобразить список, поэтому я абстрагировал первоначальный элемент списка дайджестов, чтобы мы могли повторно использовать его и убедиться, что наши элементы списка имеют одинаковый внешний вид во всем приложении.
Widget recipesList() {
final repository = Provider.of<MemoryRepository>(context);
var recipes = repository.findAllRecipes();
return ListView.builder(
itemCount: recipes.length,
itemBuilder: (context, index) {
var listItemInfo = ListItemInfo(
id: recipes[index].link,
author: recipes[index].source,
title: recipes[index].title,
titleImage: Image.network(recipes[index].thumbnail),
showAddIcon: false,
);
return ListItem(listItemInfo);
},
);
}
Widget recipeSearchResultsList() {
var searchResultRecipes = _searchResults.data.length > 0
? Recipe.fromSerpApiResultJson(_searchResults.data)
: <Recipe>[];
final repository = Provider.of<MemoryRepository>(context);
return ListView.builder(
itemCount: searchResultRecipes.length,
itemBuilder: (context, index) {
var listItemInfo = ListItemInfo(
id: searchResultRecipes[index].link,
author: searchResultRecipes[index].source,
title: searchResultRecipes[index].title,
titleImage: Image.network(searchResultRecipes[index].thumbnail),
showAddIcon: true,
onTap: () => {
repository.addRecipe(searchResultRecipes[index]),
Navigator.pop(context)
},
);
return ListItem(listItemInfo);
},
);
}
Scope Creep (Осторожно — ЮТНИ, он вам вряд ли понадобится)
Для меня это было самое заманчивое время, чтобы попытаться перепроектировать проект, поскольку в нем все еще отсутствует ряд ключевых вещей.
Я хотел сделать больше работы над:
- доступ к данным, включая пакетные запросы API
- создавайте гораздо лучшие виджеты с красивой анимацией
- добавить тему и вкус
- Ведение журнала
- Автоматизированное приемочное тестирование.
- Улучшить дизайн для Android
- Посмотрите, как это будет работать в качестве веб-сайта
- ввести несколько библиотек управления состоянием
- и т. д..
Но опыт подсказывает мне, что нужно сопротивляться желанию отвлечься, даже некоторые первоначальные исследования в Google значительно замедлили этот пост.
В конце концов, я вернулся к демонстрационному менталитету, чтобы заставить его работать, сбалансированному с советом дяди Боба, что, как только это работает, это только 50%, теперь вам нужно сделать это правильно.
Это равнялось еще некоторому времени извлечения методов и уборки.
Пока мы даем каждому классу и методу единственную ответственность в своем собственном файле, мы можем легко улучшить их независимо позже, когда мы переходим от концепции к готовому продукту.
Часто расползание масштаба происходит, когда мне надоедает дисциплина текущей задачи, поскольку дисциплины кажутся медленными.
Ссылки
- Добавьте панель вкладок и панель навигации в стиле iOS в ваше следующее приложение Flutter
- Добавить высоту к любому виджету
Большое спасибо M4trix Dev, так как его статья о панели вкладок iOS была неоценимой и позволила мне быстро исправить проблемы, которые у меня были с моей первой реализацией.
Люди
«Дело в том, что очень легко быть другим, но очень трудно быть лучше».
Джони Айв_
Звук и изображение
Еще кое-что
«Каждое утро я смотрел в зеркало и спрашивал себя: «Если бы сегодня был последний день моей жизни, хотел бы я делать то, что собираюсь сделать сегодня?» И всякий раз, когда ответ был «Нет» слишком много дней подряд, я знаю, что мне нужно что-то изменить».
Стив Джобс_