Как сделать приложение погода
Привет! В этой статье я познакомлю вас с кроссплатформенной разработкой приложений на Flutter.
Я покажу, как работать с сетью, расскажу, что такое BLoC, и на примере получения геолокации покажу, как работать с нативной частью приложения. Я подразумеваю, что у вас уже есть какие-то навыки программирования и не буду объяснять базовые вещи.
Для тех кто не хочет читать много текста есть ссылка на репозиторий GitHub.
Для начала давайте установим Flutter. Как это сделать – вы можете узнать об этом на официальном сайте Flutter.
Инициализируем стартовый шаблон приложения с помощью CLI Flutter. Для этого выполним в терминале:
All done! [✓] Flutter: is fully installed. (Channel stable, 1.20.3, on Mac OS X 10.15.5 19F101, locale ru-RU) [!] Android toolchain - develop for Android devices: is partially installed; more components are available. (Android SDK version 29.0.3) [✓] Xcode - develop for iOS and macOS: is fully installed. (Xcode 11.7) [✓] Android Studio: is fully installed. (version 4.0) [!] VS Code: is partially installed; more components are available. (version 1.48.2) [!] Connected device: is not available. Run "flutter doctor" for information about installing additional components. In order to run your application, type: $ cd WeatherApp $ flutter run Your application code is in WeatherApp/lib/main.dart.flutter doctor – утилита для проверки, что Flutter установлен правильно
Проверим, что всё работает нормально:
- Открываем проект в Android Studio. Обратите внимание, что для работы с Flutter в Android Studio нужно установить плагин flutter.
- Запускаем эмулятор или подключаем реальное устройство.
- Запускаем проект Run → Debug.
Как и любой современный фреймворк Flutter имеет свой менеджер пакетов – Pub. Для того чтобы установить необходимые зависимости давайте добавим их в файл pubspec.yaml в конец секции dependecies:
После чего нам необходимо их установить. Для этого выполним в терминале команду:
Информацию о погоде мы будем получать с сервиса OpenWeatherMap. Для начала вам необходимо зарегистрироваться, чтобы получить ключ для работы с API на почту. Давайте опишем сервис для работы с API:
У нас будут два метода fetchCurrentWeather – метод получения текущей погоды и fetchHourlyWeather – метод получения погоды по часам.
Опишем модель данных о погоде:
В Dart асинхронные запросы всегда возвращаются в виде Future. Если говорить совсем коротко, то это данные которые будут доступны «в будущем». То есть, мы выполнили запрос, но, для того, чтобы клиент получил ответ от сервера должно пройти какое-то время, и чтобы интерфейс пользователя не блокировался мы должны обработать этот ответ специальным образом, таким как BLoC.
Существует множество разных паттернов отделения бизнес-логики от UI компонента: MVC, MVP, MVVM и так далее. Во Flutter чаще всего принято использовать BLoC, что расшифровывается как Business logic component. Суть этих «блоков», чтобы сделать event-driven архитектуру приложения. Для начала опишем список состояний компонента с погодой:
// lib/states/WeatherState.dart abstract class WeatherState extends Equatable < const WeatherState(); @override List<Object> get props => []; >class WeatherInitial extends WeatherState <> class WeatherLoadInProgress extends WeatherState <> class WeatherLoadSuccess extends WeatherState < final Weather weather; final List<Weather> hourlyWeather; const WeatherLoadSuccess( <@required this.weather, @required this.hourlyWeather>) : assert(weather != null); @override List<Object> get props => [weather]; > class WeatherLoadFailure extends WeatherState <>@required>Мы описали 4 состояния:
- WeatherInitial – когда не происходит ничего
- WeatherLoadInProgress – когда мы загружаем данные о погоде
- WeatherLoadSuccess – когда данные загружены успешно
- WeatherLoadFailure – когда произошла какая-то ошибка
Далее нам необходимо описать события которые будет обрабатывать BLoC:
// lib/events/WeatherEvent.dart abstract class WeatherEvent extends Equatable < const WeatherEvent(); >class WeatherRequested extends WeatherEvent < final String city; final String lat; final String lon; const WeatherRequested(Сейчас нам достаточно одного события – WeatherRequested. Это событие для того, чтобы BLoC понимал что необходимо запрашивать данные о погоде по названию города.
Опишем сам BLoC:
// lib/bloc/WeatherBloc.dart class WeatherBloc extends Bloc<WeatherEvent, WeatherState> <>Для реализации BLoC мы выбрали библиотеки bloc и flutter_bloc. Как видим наш «блок» это просто класс который наследуется от дженерика Bloc из библиотеки Bloc. «Блок» принимает два типа:
- WeatherEvent – события которые он будет обрабатывать
- WeatherState – состояния в которых он может быть
Теперь нам необходимо реализовать метод mapEventToState для обработки событий в «блоке»:
class WeatherBloc extends Bloc<WeatherEvent, WeatherState> < @override Stream<WeatherState> mapEventToState(WeatherEvent event) async* < if (event is WeatherRequested) < yield WeatherLoadInProgress(); try < final Weather weather = await WeatherService.fetchCurrentWeather(query: event.city); final List<Weather> hourlyWeather = await WeatherService.fetchHourlyWeather(query: event.city); yield WeatherLoadSuccess( weather: weather, hourlyWeather: hourlyWeather); >catch (_) < yield WeatherLoadFailure(); >> > >И добавим в конструктор блока стандартное состояние:
final String cityName; WeatherBloc(this.cityName) : super(null) < add(WeatherRequested(city: cityName)); >Метод add() добавляет событие в блок и это событие обрабатывается методом mapEventToState.
Вот так выглядит наш полный «блок»:
// lib/bloc/WeatherBloc.dart import 'package:WeatherApp/events/WeatherEvent.dart'; import 'package:WeatherApp/models/Weather.dart'; import 'package:WeatherApp/services/WeatherService.dart'; import 'package:WeatherApp/states/WeatherState.dart'; import 'package:bloc/bloc.dart'; class WeatherBloc extends Bloc<WeatherEvent, WeatherState> < final String cityName; WeatherBloc(this.cityName) : super(null) < add(WeatherRequested(city: cityName)); >@override Stream<WeatherState> mapEventToState(WeatherEvent event) async* < if (event is WeatherRequested) < yield WeatherLoadInProgress(); try < final Weather weather = await WeatherService.fetchCurrentWeather(query: event.city); final List<Weather> hourlyWeather = await WeatherService.fetchHourlyWeather(query: event.city); yield WeatherLoadSuccess( weather: weather, hourlyWeather: hourlyWeather); >catch (_) < yield WeatherLoadFailure(); >> > >Сделаем карточку погоды. Карточка должна отображать температуру, иконку и произвольный заголовок.
Нам также понадобится компонент для отображения погоды по часам:
Сделаем компонент для главной страницы, который будет в себя включать виджет с текущей погодой и горизонтальный скролл с погодой по часам:
// lib/main.dart void main() < runApp(MyApp()); >class MyApp extends StatelessWidget < @override Widget build(BuildContext context) < return MaterialApp( theme: ThemeData( primaryColorDark: Colors.white, primaryColor: Colors.white, ), home: MyHomePage(), ); >> class MyHomePage extends StatefulWidget < const MyHomePage(Есть несколько способов работы с BLoC, мы будем использовать BlocProvider. Разберем несколько строк кода:
Scaffold – компонент для стандартного интерфейса MaterialDesign: Шапка/Тело/Навигация и FloatingButton.
create: (context) => WeatherBloc('Berlin') – здесь мы создаем наш объект «блока» и передаем туда значение по умолчанию.
child: BlocBuilder<WeatherBloc, WeatherState>( builder: (context, state) <Под капотом BlocBuilder это обычный StatefulWidget. Он имеет колбек builder, который вызывается каждый раз когда внутри WeatherBloc вызывается метод mapEventToState и возвращает новое значение, тем самым заставляя компонент перерисовываться. Внутри builder у нас есть проверка состояния компонента, которая будет рисовать компонент только если данные получены успешно:
У Flutter есть метод showSearch который открывает окно поиска по гайдлайнам MaterialDesign.
В шапке Scaffold мы добавили иконку поиска по клику на которую вызывается окно поиска:
return BlocProvider( create: (context) => WeatherBloc('Berlin'), child: BlocBuilder<WeatherBloc, WeatherState>( builder: (context, state) < if (state is WeatherLoadSuccess) < return Scaffold( appBar: AppBar( elevation: 0, backgroundColor: Color.fromRGBO(0, 0, 0, 0), actions: [ IconButton( icon: Icon(Icons.search), onPressed: () < showSearch( context: context, delegate: MySearchDelegate((query) < BlocProvider.of<WeatherBloc>(context).add(WeatherRequested(city: query)); >)); >, ) ], ),Открытие окна происходит с помощью метода showSearch, который принимает в себя текущий контекст приложения и класс SearchDelegate который будет обрабатывать результат поиска. Давайте напишем свой SearchDelegate:
class MySearchDelegate extends SearchDelegate < String selectedResult; final Function callback; MySearchDelegate(this.callback); @override List<Widget> buildActions(BuildContext context) < return [ IconButton( icon: Icon(Icons.close), onPressed: () < query = ""; >, ), ]; > @override Widget buildLeading(BuildContext context) < return IconButton( icon: Icon(Icons.arrow_back), onPressed: () < Navigator.pop(context); >, ); > @override Widget buildResults(BuildContext context) < return Container( child: Center( child: Text(selectedResult), ), ); >@override void showResults(BuildContext context) < selectedResult = query; callback(query); close(context, query); >@override Widget buildSuggestions(BuildContext context) < List<String> searchResults = ["Helsinki", "Moscow", "Berlin", "New York", "Saint Petersburg", query].where((element) => element.contains(query)).toList(); return ListView.builder( itemCount: searchResults.length, itemBuilder: (context, index) < return ListTile( title: Text(searchResults[index]), onTap: () < selectedResult = searchResults[index]; callback(selectedResult); Navigator.pop(context); >, ); >, ); > >Здесь у нас четыре метода:
- buildActions – возвращает компонент, который отображается справа строки поиска. У нас это кнопка удаление текущего ввода.
- buildLeading – возвращает компонент, который отображается слева шапки (например, стрелка назад).
- buildSuggestions – обрабатывает то, что вводит пользователь.
- buildResults – вызывается, когда был вызван метод showResults.
Мы также описали колбек который будет вызываться когда пользователь выбрал какой-то город или нажал поиск на клавиатуре:
В lib/main.dart мы описали его так:
Мы получаем результат ввода пользователя и кидаем событие WeatherRequested для WeatherBloc после чего происходит ререндер всего экрана.
Посмотрим на результат:
Для того, чтобы определить геолокацию пользователя мы используем библиотеку geolocator.
Для того, чтобы она заработала нам необходимо добавить специальные разрешения в нативные части приложения под iOS и Android. О том как это сделать описано в документации библиотеки geolocator.
Для начала добавим новое событие в файл lib/events/WeatherEvent.dart:
// lib/events/WeatherEvent.dart class WeatherCurrentPositionRequested extends WeatherEvent < const WeatherCurrentPositionRequested() : super(); @override List<Object> get props => []; >Отредактируем файл lib/bloc/WeatherBloc.dart.
Создадим метод _newWeatherRequested:
Stream<WeatherState> _newWeatherRequested(WeatherRequested event) async* < yield WeatherLoadInProgress(); try < final Weather weather = await WeatherService.fetchCurrentWeather( query: event.city, lon: event.lon, lat: event.lat); final List<Weather> hourlyWeather = await WeatherService.fetchHourlyWeather( query: event.city, lon: event.lon, lat: event.lat); yield WeatherLoadSuccess(weather: weather, hourlyWeather: hourlyWeather); >catch (_) < yield WeatherLoadFailure(); >>Также сделаем новый обработчик события для определения текущей локации:
Stream<WeatherState> _newWeatherCurrentPositionRequested() async* < LocationPermission permission = await checkPermission(); if (permission == LocationPermission.whileInUse || permission == LocationPermission.always) < Position lastKnownPosition = await getLastKnownPosition(); if(lastKnownPosition != null) < add(WeatherRequested( lat: lastKnownPosition.latitude.toString(), lon: lastKnownPosition.longitude.toString())); >else < Position position = await getCurrentPosition(desiredAccuracy: LocationAccuracy.high); add(WeatherRequested( lat: position.latitude.toString(), lon: position.longitude.toString())); >> else < await requestPermission(); add(WeatherCurrentPositionRequested()); >>Здесь мы проверяем права на локацию, если прав нет, то просто запрашиваем.
What You'll Be CreatingМногие популярные приложения прогноза погоды в Google Play либо содержат много рекламы, либо требуют слишком большого количества разрешений, либо содержат функционал, который большинство из нас никогда не используют. Было бы здорово, если бы мы могли создать собственное приложение погоды с нуля?
В этом уроке я покажу вам, как это сделать. Наше приложение будет иметь простой и минималистичный пользовательский интерфейс, показывающий пользователю именно то, что ему нужно знать о текущих погодных условиях. Давайте начнем.
1. Подготовка
Прежде чем продолжить, дважды проверьте, что у вас установлены следующие компоненты:
- Eclipse ADT Bundle: вы можете скачать его на веб-сайте разработчика Android.
- Ключ APIOpenWeatherMap : это не обязательно для выполнения нашей задачи, но это бесплатно. Вы можете получить его, зарегистрировавшись на сайте OpenWeatherMap.
- Иконки: Я рекомендую вам скачать шрифт weather icons font, созданный Эриком Флорсом. Вам нужно загрузить файл TTF, потому что мы будем использовать его в нативном приложении. Мы будем использовать этот шрифт чтобы показывать различные значки в зависимости от погодных условий.
2. Создадим новый проект
Я собираюсь назвать это приложение SimpleWeather, но вы можете дать ему любое имя, которое вам понравится. Введите уникальное имя пакета, установите минимальный необходимый SDK на Android 2.2 и установите целевой SDK на Android 4.4. Вы можете оставить тему Holo Dark.
Это приложение будет иметь только одно Activity , и оно будет основано на шаблоне Blank Activity, как показано ниже.
Назовите Activity WeatherActivity. Мы будем использовать Fragment внутри этого Activity . Макет, связанный с Activity называется activity_weather.xml. Макет, связанный с Fragment называется fragment _weather.xml.
3. Добавим пользовательский шрифт
Скопируйте weathericons-regular-webfont.ttf в каталог assets/fonts вашего проекта и переименуйте его в weather.ttf.
4. Отредактируем файл манифеста
Единственное разрешение, которое требуется этому приложению - это android.permission.INTERNET .
Чтобы упростить этот урок, мы рассмотрим только портретный режим. Узел activity манифеста должен выглядеть так:
5. Отредактируем макет Activity
6. Отредактируем макет Fragment
Измените файл fragment_weather.xml, добавив пять тегов TextView , чтобы отобразить следующую информацию:
- город и страна
- текущая температура
- значок, показывающий текущее погодное условие
- отметка времени, указывающая пользователю, когда было получено последнее обновление информация о погоде
- более подробная информация о текущей погоде, например, описание и влажность
Используйте RelativeLayout для размещения текстовых представлений. Вы можете настроить textSize для различных устройств.
7. Изменим strings.xml
Этот файл содержит строки, используемые в нашем приложении, а также коды символов Юникода, которые мы будем использовать для отображения значков погоды. Приложение сможет отображать восемь различных типов погодных условий. Если вам нужно больше, примените следующую хитрость. Добавьте следующие значения в файл values/strings.xml:
8. Добавим пункт меню
Пользователь должен иметь возможность выбирать город, чью погоду они хотят видеть. Измените файл menu/weather.xml и добавьте элемент для этой опции.
Теперь, когда все XML-файлы готовы к использованию, давайте перейдем к запросу на API OpenWeatherMap для получения данных о погоде.
9. Получаем данные из OpenWeatherMap
Мы можем получить текущие данные о погоде в любом городе, в формате JSON, с помощью API OpenWeatherMap. В строке запроса мы передаем имя города и систему измерения, в которой должны быть результаты.
Ответ, который мы получаем через API, выглядит так:
Создайте новый класс Java и назовите его RemoteFetch.java. Этот класс отвечает за получение данных о погоде через API OpenWeatherMap.
Мы используем BufferedReader для чтения ответа API в StringBuffer . Когда мы получим полный ответ, мы преобразуем его в объект JSONObject .
Как видно из приведенного выше ответа, данные JSON содержат поле с именем cod . Его значение равно 200 , если запрос был успешным. Мы используем это значение, чтобы проверить, имеет ли ответ JSON текущую информацию о погоде или нет.
Класс RemoteFetch.java должен выглядеть следующим образом:
10. Сохраним город в настройках
Пользователь не должен указывать имя города каждый раз, когда захочет использовать приложение. Приложение должно запомнить последний город, который искал пользователь. Мы делаем это, используя SharedPreferences . Однако вместо прямого доступа к этим настройкам из нашего класса Activity , для этого лучше создать отдельный класс.
Создайте новый класс Java и назовите его CityPreference.java. Чтобы сохранить и получить имя города, создайте два метода setCity и getCity . Объект SharedPreferences инициализируется в конструкторе. Класс CityPreference.java должен выглядеть следующим образом:
11. Создадим Fragment
Создайте новый класс Java и назовите его WeatherFragment.java. В этом фрагменте в качестве макета используется frag_weather.xml. Объявите пять объектов TextView и инициализируйте их в методе onCreateView . Объявите новый объект Typeface с именем weatherFont . Объект TypeFace указывает на веб-шрифт, который вы загрузили и сохранили в папке assets/fonts.
Мы будем использовать отдельный Thread для асинхронного получения данных через API OpenWeatherMap. Мы не можем обновить пользовательский интерфейс из подобного фонового потока. Поэтому нам нужен объект Handler , который мы инициализируем в конструкторе класса WeatherFragment .
Инициализируем объект weatherFont , вызывая createFromAsset в классе Typeface . Мы также вызываем метод updateWeatherData в onCreate .
Только основной поток разрешает обновлять пользовательский интерфейс приложения для Android. Вызов Toast или renderWeather прямо из фонового потока приведет к ошибке выполнения. Вот почему мы вызываем эти методы с использованием метода post - обработчика .
Метод renderWeather использует данные JSON для обновления объектов TextView . Узел weather ответа JSON представляет собой массив данных. В этом уроке мы будем использовать только первый элемент массива метеорологических данных.
В конце метода renderWeather мы вызываем setWeatherIcon с идентификатором текущей погоды, а также временем восхода и захода солнца. Настройка значка погоды немного сложна, потому что API OpenWeatherMap поддерживает больше погодных условий, чем мы можем отобразить с помощью используемого веб-шрифта. К счастью, идентификаторы погоды следуют шаблону, о котором вы можете узнать больше на веб-сайте OpenWeatherMap.
Так мы будем сопоставлять идентификатор погоды с иконкой:
- коды погоды в диапазоне 200 обозначают грозу, что означает, что мы можем использовать R .string.weather_thunder для них
- коды погоды в диапазоне 300 связаны с моросями, и мы используем R.string.weather_drizzle
- коды погоды в диапазоне 500 означают дождь, и мы используем R.string.weather_rain
- и так далее .
Мы используем время восхода и захода солнца, чтобы отобразить солнце или луну, в зависимости от текущего времени суток и только в том случае, если погода ясная.
Конечно, вы можете обрабатывать больше погодных условий , соответственно изменяя метод setWeatherIcon .
Наконец, добавим метод changeCity к фрагменту, чтобы пользователь мог обновить текущий город. Метод changeCity будет вызываться только из основного класса Activity .
12. Редактируем Activity
В течении настройки проекта, Eclipse заполняет WeatherActivity.java некоторым шаблонным кодом. Замените стандартную реализацию метода onCreate на приведенную ниже, в которой мы используем WeatherFragment . Метод onCreate должен выглядеть следующим образом:
Затем отредактируйте метод onOptionsItemSelected и обработайте единственный параметр меню, который у нас есть. Все, что вам нужно сделать, это вызвать метод showInputDialog .
В методе showInputDialog мы используем AlertDialog.Builder для создания объекта Dialog , который предлагает пользователю ввести имя города. Эта информация передается методу changeCity , который хранит имя города с использованием класса CityPreference и вызывает метод changeCity во фрагменте .
Теперь ваше приложение для погоды готово. Соберите проект и установите его на Android-устройстве для тестирования.
Заключение
Теперь у вас есть полнофункциональное приложение прогноза погоды. Изучайте API OpenWeatherMap для дальнейшего развития вашего приложения. Вы также можете использовать больше значков погоды, так как в примере мы используем только немногие из них.
Многие популярные погодные приложения в Google Play либо полны рекламы, требуют слишком много разрешений, либо содержат функции, которые большинство из нас никогда не используют. Не было бы замечательно, если бы вы могли создать собственное приложение погоды с нуля?
В этом уроке я собираюсь показать вам, как. Наше приложение будет иметь простой и минималистичный пользовательский интерфейс, показывающий пользователю именно то, что ему нужно знать о текущих погодных условиях. Давайте начнем.
Ищете ярлык?
Из этого туториала вы узнаете, как создать приложение погоды с нуля, но одной из альтернатив является использование одного из шаблонов приложения погоды Android на Envato Market.
Например, Weminder предоставляет простой, понятный пользовательский интерфейс и все основные функции погодного приложения, так что вы можете настроить его для своих собственных целей.
Или, если вы хотите что-то уникальное и специально разработанное, отправляйтесь в Envato Studio, чтобы проверить ассортимент предлагаемых здесь мобильных услуг и услуг по разработке приложений .
1. Предпосылки
Прежде чем продолжить, дважды проверьте, что у вас есть следующие настройки:
- Пакет Eclipse ADT : вы можете скачать его на сайте разработчика Android .
- Ключ API OpenWeatherMap : Это не обязательно для завершения учебника, но это бесплатно. Вы можете получить его, зарегистрировавшись на сайте OpenWeatherMap .
- Иконки : я рекомендую скачать шрифт иконок погоды, созданный Эриком Флауэрсом . Вам нужно скачать файл TTF , потому что мы будем использовать его в собственном приложении. Мы будем использовать шрифт для отображения различных значков в зависимости от погодных условий.
2. Создать новый проект
Я собираюсь назвать это приложение SimpleWeather , но не стесняйтесь давать ему любое имя. Введите уникальное имя пакета, установите минимальный требуемый SDK для Android 2.2 и установите целевой SDK для Android 4.4 . Вы можете оставить тему на Holo Dark .
Это приложение будет иметь только одну Activity и оно будет основано на шаблоне пустых действий, как показано ниже.
Назовите Activity WeatherActivity . Мы будем использовать Fragment внутри этого Activity . Макет, связанный с Activity представляет собой activity_weather.xml . Макет, связанный с Fragment является фрагментом_weather.xml .
3. Добавьте пользовательский шрифт
Скопируйте weathericons-регулярно-webfont.ttf в каталог assets / fonts вашего проекта и переименуйте его в weather.ttf .
4. Отредактируйте Манифест
Чтобы этот урок был простым, мы будем поддерживать только портретный режим. Узел activity манифеста должен выглядеть следующим образом:
Приветствую всех в этот прекрасный день ожидания праздника, это моя первая статья на хабре, в которой я хотел бы рассказа про открытый API погоды Яндекса. Статья является продолжением серии Java для начинающих. Следует отметить, статья рассчитана на тех, кто недавно начал изучения язык или на тех, кто не знаком с данным сервисом, но в любом случае, рад я буду любым читателям (эх тавтология… ). Яндекс дает неплохую возможность для разработчиков, которым требуется в своей программе или на своем сайте разместить погоду, причем информации, которую Яндекс предоставляет более, чем достаточно.
Погоду Вы сможете выбрать за любой день на неделю вперед. Различные состояния (ясно, пасмурно и т. д.), множество языков (для городов, например русский и английский, для состояний все языки стран СНГ и не только: ясно, аяз, açık, ашық и т… д.), я не очень хорош в географии, но, кажется, информация там для всех стран, даже есть миниатюрные картинки состояния погоды, но самое главное, почему я выбрал этот сервис — простая и понятная структура. Сразу оговорюсь, за «рекламу» мне не платили.
Класс с внешним представлением, думаю описывать не надо, я лишь приведу код, чтобы потом не было несостыковок. Рекомендую даже не списывать, а сделать свой, ибо мой убогий:
Еще я бы добавил для удобства всплывающее меню, чтобы айди города каждый раз не набирать:
Естественно добавить нужно не один город, но мне пока хватает Пензы. Для добавления городов в меню лучше создать отдельный класс, но это другая тема, я с этим возиться не стал.
Следующий класс, который я создал — класс Weather для хранения переменных с информацией о погоде. Тут ничего сложного:
Далее создаем документ для парсинга
Т.е. получилось у нас что-то типа:
Что ж связали и разобрали, пора извлекать непосредственно погоду. Как видим у forecast есть наследник fact, а в нем в свою очередь — station и temperature (в названии города иногда указывается аэропорт). Теперь из station и temperature вытащим погоду и название города:
Циклом for перебираем всех детей и выбираем лишь нужных нам, как видите я еще выбрал влажность (humidity) и тип картинки. В остальном думаю все предельно понятно.
Осталось лишь написать обработчик события для кнопки:
В заключении хотелось бы попросить прощения за быдлокодинг в некоторых местах, буду рад если ткнете носом в таковой. Еще одна проблема, которая возникла у меня и которую я так и не решил — отображение картинки, которая появляется лишь если растянуть форму. Так что готов выслушать любую обоснованную критику.
Читайте также: