Введение
Общее описание
Структура приложения
Уроки
Урок 1
Создание приложения, экраны, меню, список, локализация
Урок 2
Просмотр видео (youtube), панель ввода
Урок 3
Карты, PlusMinus, пользовательская обработка экранов
Урок 4
Завершение разработки, закрепление материала
Урок 5
Интро, авторизация, фото
Урок 6
Боковое меню, горизонтальный список, пагинация, раскрывающийся список, баркод-сканер, распознавание речи, поиск, листание страниц
Урок 7
Работа с базами данных SQLite, свайп, componentDateDiapason
Урок 8
Спиннер, календарь, пиккер и события
Урок 9
Работа с пуш сообщениями, BadgeTextView
Урок 10
Анимация, кастомные компоненты
Описание библиотеки
Приложения

Урок 2

На этом уроке мы закрепим пройденный материал, рассмотрим другие способы его применения и научимся работать с такими компонентами как просмотр видео (youtube), панель ввода. Также рассмотрим способы передачи данных между экранами

Постановка задачи (задание урока)

Нужно описать все экраны, на которые можно перейти с экрана HOME.

Их дизайн приведен на следующих рисунках:

Рис. 1 экран CATEGORY
Рис. 1 экран CATEGORY
Рис. 2 экран PRODUCT
Рис. 2 экран PRODUCT
Рис. 3 экран PRODUCT
Рис. 3 экран PRODUCT
Рис. 4 экран ITEM_FORM
Рис. 4 экран ITEM_FORM
Рис. 5 экран ITEM_FORM
Рис. 5 экран ITEM_FORM
Рис. 6 экран ITEM_FORM
Рис. 6 экран ITEM_FORM
Рис. 7 экран COMMENT
Рис. 7 экран COMMENT
Рис. 8 экран COMMENT
Рис. 8 экран COMMENT
Рис. 9 экран COUNTRY_CODE_PH
Рис. 9 экран COUNTRY_CODE_PH
Рис. 10 экран THANKS
Рис. 10 экран THANKS
Рис. 11 экран YOUTUBE
Рис. 11 экран YOUTUBE

На рисунках 2 и 3 изображены разные части одного и того же экрана (PRODUCT). На рисунках 4, 5 и 6 также изображен один экран (ITEM_FORM) в двух состояниях - не заполненном и заполненном. Аналогично и экраны на рисунках 7 и 8 (COMMENT).

Описание API

Экран CATEGORY URL depro/products/list, параметр “categoryId”, ответ 
[
    {
        "productId":511,
        "title":"Опрокидыватель контейнеров грузоподъёмностью 1300 кг",
        "mainImagePath":"images/viber-image1.jpg"
    },
    {
        "productId":1450,
        "title":"Стол из нержавеющей пищевой стали",
        "mainImagePath":"images/Stol-20170119_112847_resized.jpg"
    },
    ...
]

Экран PRODUCT URL depro/products/prodbyid,  параметр “productId”, ответ
{
    "categoryId":39,
    "productId":1107,
    "mainImagePath":"images/WP_20180709_16_35_24_Pro.jpg",
    "imagePaths":["images/WP_20180709_15_31_38_Pro.jpg","images/WP_20180709_15_31_51_Pro.jpg",
                    "images/WP_20180709_15_32_05_Pro.jpg","images/WP_20180709_16_35_24_Pro.jpg"],
    "videoLink":"https://youtu.be/77o8DycDNo8",
    "title":"Умный мусорный бак (что говорит)",
    "description":
        {
            "text1":"Наша компания ООО Системы модернизации складов - предлагает для ...",
            "text2":"”,
            "characteristics":[{"title":"Объем","value":"1,5 куб"},{"title":"Подключение","value":"380 В"}]
        }
}

Экран ITEM_FORM URL depro/send/buy, метод POST отправка данных
    {"name":"Иван","phone":"+38055555","comment":"Роот щшл","productId":"1107"}
    Ответ {"result":"oK"}

При клике на какую нибудь категорию на экране HOME осуществляется переход на экран CATEGORY на котором отображаются все продукты (товары) в категории. Перед списком отображается название категории и количество продукции в категории. После количества продуктов стоит слово “товар(ов или а)”. Текст устанавливается в зависимости от числа, например: 1 товар, 2 товара, 7 товаров.

При клике на стрелку влево осуществляется возврат на предыдущий экран.

При выборе какого нибудь товара показывается экран (PRODUCT) с детальной информацией о нем. Клик на “полное описание” работает аналогично как на экране ABOUT. Кнопка и текст “Посмотреть видео” показываются только если в данных поле videoLink не пустое. При клике на нем осуществляется переход на экран YOUTUBE. Список “Основные характеристики” также показывается если поле description.characteristics не пустое. Каждая четная строка имеет серый фон. Помним, что нумерация начинается с нуля. При клике на “Оставить заявку” осуществляется переход на экран ITEM_FORM.

Экран ITEM_FORM служит для ввода информации о клиенте и передачи данных заказа на сервер для обработки. Поле “комментарий” не обязательное. Поле Имя не меньше 1 символа, поле “номер телефона” не менее 5 цифр. При клике на поле с кодом страны вызывается экран COUNTRY_CODE_PH. При клике на поле “Добавить комментарий” осуществляется переход на экран COMMENT. При этом становится недоступной кнопка “Добавить комментарий” она заменяется на текст “Ваш комментарий” и появляется кнопка “Править” (рис. 6) при клике на которую появляется экран COMMENT для правки комментария.Кнопка “Отправить” становится доступной если введены правильные значения имени и номера телефона. При клике на нее на сервер передаются поля: name, phone, comment, productId в формате json. Телефон отправляется в виде "+38055555" - код страны + номер. При получении ответа с сервера с подтверждением приема данных осуществляется переход на экран THANKS. При клике на кнопку “продолжить” экрана THANKS осуществляется переход на экран HOME. В реальном приложении после отправки заявки на протяжении часа менеджер компании звонит клиенту на указанный им телефон и уточняет информацию для оформления сделки. В нашем примере, естественно, никто не будет звонить.

Работа экрана COMMENT понятна. Экран COUNTRY_CODE_PH показывает список кодов стран (из смартфона). В начале списка располагаются страны указанные на дизайне. Они выделены жирным. При клике на нужную страну осуществляется возврат назад и устанавливается код страны в соответствующее поле. Экран YOUTUBE выводится на весь экран, фон полупрозрачный.

Описание экранов

Новые экраны используют и новые данные с сервера. Поэтому в класс API.java внесем для них адреса:

    public static String PRODUCTS = "depro/products/list";
    public static String DETAIL = "depro/products/prodbyid";
    public static String MARKER_MAP = "depro/services/markers";
    public static String REPAIRS = "depro/services/service";
    public static String NEWS_DETAIL = "depro/news/newsbyid";
    public static String SEND_PRODUCT = "depro/send/buy";
    public static String SEND_FEEDBACK = "depro/send/feedbackRequest";
    public static String SEND_SERVICES = "depro/send/requestServices";

Добавим в класс MyDeclareScreens.java описание всех указанных в постановке экранов (приведены ниже), а затем поясним новые компоненты.

    fragment(CATEGORY, R.layout.fragment_category).animate(AS.RL)
        .navigator(back(R.id.back))
        .component(TC.PANEL,
            model(ARGUMENTS),
            view(R.id.panel))
        .list(model(API.PRODUCTS, "categoryId").errorShowView(R.id.error_view),
            view(R.id.recycler, R.layout.item_category).noDataView(R.id.no_product),
            navigator(start(0, PRODUCT)));

    fragment(PRODUCT, R.layout.fragment_product).animate(AS.RL)
        .navigator(back(R.id.back),
            handler(R.id.apply, ITEM_FORM, PS.RECORD_COMPONENT, R.id.panel))
        .component(TC.PANEL,
            model(API.DETAIL, "productId"),
            view(R.id.panel).visibilityManager(visibility(R.id.video, "videoLink"),
                visibility(R.id.full_desc, "description.text2"),
                visibility(R.id.charact, "description.characteristics")),
            navigator(handler(R.id.video, VH.SET_PARAM), start(R.id.video, YOUTUBE),
                showHide(R.id.full_desc, R.id.text2, R.string.hide, R.string.full_desc)));

    fragment(ITEM_FORM, R.layout.fragment_item_form).animate(AS.RL)
        .navigator(back(R.id.back))
        .component(TC.PANEL_ENTER,
            model(ARGUMENTS),
            view(R.id.panel),
            navigator(handler(R.id.country, COUNTRY_CODE_PH, after(assignValue(R.id.codePlus))),
                handler(R.id.add_comment, COMMENT, PS.RECORD, "comment",
                    after(assignValue(R.id.comment), show(R.id.panel_comment))),
                handler(R.id.edit, COMMENT, PS.RECORD, "comment", after(assignValue(R.id.comment))),
                handler(R.id.apply, VH.CLICK_SEND,
                    model(POST, API.SEND_PRODUCT, "name,phone,comment,productId"),
                    after(start(THANKS)))))
        .enabled(R.id.apply, R.id.name,  R.id.phone);

    activity(COUNTRY_CODE_PH, R.layout.activity_country_code).animate(AS.BT)
        .navigator(back(R.id.back))
        .list(model(COUNTRY_CODE, "380,48,995,374,994"),
            view(R.id.recycler, "isPopular", new int[] {R.layout.item_country_code, 
                R.layout.item_country_code_pop}),
            navigator(handler(0, VH.RESULT_RECORD)));

    activity(COMMENT, R.layout.activity_comment).animate(AS.RL)
        .navigator(back(R.id.back),
            handler(R.id.apply, VH.RESULT_RECORD, "comment"))
        .component(TC.PANEL_ENTER,
            model(ARGUMENTS),
            view(R.id.panel_comment))
        .enabled(R.id.apply, R.id.comment);

    activity(YOUTUBE, YouTubeActivity.class).animate(AS.RL)
        .navigator(back(R.id.cancel))
        .componentYoutube(R.id.player)
        .setValue(item(R.id.player, TS.PARAM, "videoLink"));

    fragment(THANKS, R.layout.fragment_thanks).animate(AS.RL)
        .navigator(setMenu(R.id.apply), keyBack(R.id.apply));

Как видно с дизайна экран YOUTUBE должен быть типа activity (он больше чем контейнер фрагментов в экране MAIN и перекрывает все его элементы). Кроме того у него полупрозрачный фон. В настоящее время в андроид установить тему можно только в манифесте. Поэтому в описании экрана указан кастомный класс активности YouTubeActivity.class, который имеет вид:

public class YouTubeActivity extends BaseActivity {
    @Override
    public int getLayoutId() {
        return R.layout.activity_youtube;
    }
}

Класс YouTubeActivity нужно создать

Хотя это и маленькая (по количеству кода activity), но все же это кастомная activity. Поэтому в манифесте указывается:

<activity android:name=".YouTubeActivity"
   android:theme="@style/Theme.Transparent"
   android:screenOrientation="portrait"/>

И, естественно, нужно получить ключ разработчика. Детальная инструкция находится здесь. Ключ разработчика нужно задать в параметре youtubeApiKey (в виде строчного ресурса ы котором находится ключ) класса MyAppParams.java

В библиотеке декларативного программирования DePro имеется возможность посмотреть Youtube и с помощью родного приложения от Google. Для этого в навигаторе нужно задать следующий обработчик:

    startYoutube(R.id.video, "videoLink")
вместо двух:
    handler(R.id.video, VH.SET_PARAM), start(R.id.video, YOUTUBE)

Данный способ имеет несколько преимуществ перед предыдущим, а именно:

    1. Не нужно описывать экран для Youtube.
    2. Не нужно вносить изменения в манифест.
    3. Не нужно получать ключ разработчика.
    4. используется только один обработчик в навигаторе, вместо двух ( handler(R.id.video, VH.SET_PARAM) и start(R.id.video, YOUTUBE) ).

Недостаток у этого метода только один: нельзя задать свой дизайн экрана с видео (показывается экран приложения Google)

Если все введено правильно, то при старте приложения будут отображаться (и работать) все указанные экраны. Видео имеется не для всей номенклатуры продукци. Нужно смотреть у которых есть поле "Посмотреть видео" и на нем кликнуть. Проверить работу компонента componentYoutube можно на экране ABOUT, либо для категории "разное" выбрать продукцию "Умный мусорный бак". Там точно есть видео.
А теперь объясним те новые конструкции, которые были использованы при описании экранов урока.

Объяснение работы новых компонентов

Экран CATEGORY

Функционал .animate(AS.RL) указывает анимацию выхода экрана справа налево (RL). Обработчик back(R.id.back) указывает, что при клике на R.id.back будет осуществлен выход с экрана. На первом уроке мы описали, что при клике на какую нибудь категорию будет вызван экран CATEGORY и ему будет передана соответствующая запись. А в модели можно получить эту запись указав метод ARGUMENTS.

Как видно с разметки экрана .component(TC.PANEL, отображает два поля: название категории и количество товаров в ней. В разметке для количества товаров применен библиотечный элемент TextViewNumberGrammar. Ему можно задать аргумент app:stringArray в котором указывается возможные значения текста. Этот элемент выводит число и в зависимости от последних цифр выводит одно из значений массива строк prod_grammar (в prod_grammar имеется три строки: товар, товара, товаров). В тех случаях когда число и текст нужно выводить отдельно (например, у них различные стили вывода), то можно использовать элемент библиотеки TextViewGrammar, который выводит только текст (без числа).

В модели model(API.PRODUCTS, "categoryId") первый параметр задает адрес (API.PRODUCTS), а второй список параметров разделенных запятой для запроса. Способ передачи параметров определяется в классе MyAppParams.java переменная typeParameterTransfer. Если typeParameterTransfer = NAME (по умолчанию), то параметры передаются в формате ?имя1=значение1&имя2=значение2, если typeParameterTransfer = SLASH, то параметры передаются в формате /значение1/значение2. В терминах Retrofit2 NAME соответствует аннотации @Query, а SLASH - аннотации @Path.

Экран PRODUCT

Здесь у нас один новый дополнительный к view функционал - visibilityManager. Он управляет видимостью элементов разметки в зависимости от значений данных. Видимость определяется методом visibility(int id элемента разметки, String имя переменной). Если переменная строкового типа, то при значении = null или = “” элемент разметки не видим. Для числовых типов элемент не видим для значений = 0. Для булевых элемент невидим если значение = false.

В частности, элемент разметки R.id.video будет виден только если для данной продукции заполненно поле "videoLink".

Как видим в описании API экрана description является классом (записью) и содержит поля "text1", "text2" и "characteristics". Библиотека позволяет работать с такими данными. В этом случае в разметке для соответствующих полей атрибут id нужно задать: description.text1, description.text2 и description.characteristics. К сожалению в коде java такую нотацию для ресурсов использовать нельзя. А в соответствии с дизайном у нас имеется необходимость показывать либо полное либо частичное описание. Управляет этим обработчик showHide(R.id.full_desc, R.id.text2, R.string.hide, R.string.full_desc)). И здесь мы не можем указывать для R.id.text2 уточнение description. Поэтому в разметке для этого элемента используем библиотечный элемент ComponTextView, которому задаем алиас description.text2. Это позволяет для биндинга данных использовать description.text2, а для работы с ресурсом в коде java использовать R.id.text2.

В разметке имеется новый библиотечный элемент Gallery, который принимает список адресов картинок и показывает их. Значения ему устанавливаются обычным образом по совпадению названий id и поля. У него имеется два атрибута indicator и placeholder. Атрибут indicator задает указатель на библиотечный элемент PagerIndicator который показывает позицию картинки в галерее. Атрибут placeholder задает изображение которое будет отображаться пока грузится картинка. Элемент PagerIndicator имеет понятные из названий атрибуты.

Также в разметке имеется интересный элемент ComponList. Он отображает список без прокрутки (очень облегчённый вариант NestedScrollView + Recycler). У него имеется атрибут itemLayoutId который указывает лайоут для отдельных элементов. Атрибут evenColor (если он есть) задает цвет фона четных элементов. Биндинг с данными осуществляется стандартно.

Экран ITEM_FORM

Имеет новый компонент типа PANEL_ENTER который предназначен для ввода данных. Его параметры model и view обычные. Новые конструкции находятся в навигаторе. Обработчик handler(R.id.country, COUNTRY_CODE_PH, after(assignValue(R.id.codePlus))) имеет дополнительный параметр after(assignValue(R.id.codePlus)), который указывает, что после вызова экрана COUNTRY_CODE_PH и возврата с него (after) данные, которые он возвратит будут присвоены элементу R.id.codePlus.

Также нужно обратить внимание, что для ввода номера телефона используется PhoneCountry, которому в атрибутах указывается минимальное количество знаков и countryView. При чтении из этого элемента данных будет отдаваться общий номер = код страны (из R.id.codePlus) + введенный номер.

В обработчике, который вызывает экран COMMENT указывается, что в экран COMMENT нужно передать запись с заданным списком полей (в нашем случае только одно поле "comment". А после возврата значений экраном COMMENT их нужно присвоить элементу разметки R.id.comment и показать панель с комментариями (show(R.id.panel_comment)). Обработчик handler(R.id.apply, VH.CLICK_SEND, model(POST, API.SEND_PRODUCT, "name,phone,comment,productId"), after(start(THANKS))))), что нужно передать данные методом POST адрес задан в API.SEND_PRODUCT, а список параметров "name,phone,comment,productId". Передаваемые параметры формируются из значений элементов разметки панели и списка общих параметров (в нашем случае это “productId”). После получения от сервера подтверждения получения данных нужно вызвать экран THANKS.

Имеется еще кострукция .enabled(R.id.apply, R.id.name, R.id.phone), которая определяет условия блокировки элемента R.id.apply. А именно, если элементы панели R.id.name и R.id.phone будут валидными, то свойство enabled элемента R.id.apply станет равным true. Как только хотя бы один элемент из списка (R.id.name, R.id.phone) станет не валидным свойство enabled станет равным false.

Экран COUNTRY_CODE_PH

Здесь у нас появляется новая конструкция model(COUNTRY_CODE, "380,48,995,374,994"). Метод COUNTRY_CODE указывает, что нужно использовать список кодов стран смартфона, а параметр "380,48,995,374,994" задает список стран, которые будут в начале списка. Обработчик handler(0, VH.RESULT_RECORD) указывает, что при клике на элемент списка (кодов стран) нужно выйти с экрана и передать запись соответствующую выбранной стране.

Экран COMMENT

Новых конструкций нет, всё знакомо.

Экран YOUTUBE

Естественно, новым компонентом здесь является .componentYoutube(R.id.player). Ему передается только один параметр, а именно, R.id.player, который указывает элемент разметки для просмотра видео - ComponYouTubePlayer. После задания адреса видео (.setValue(item(R.id.player, TS.PARAM, "videoLink")) ) видео готово к показу. Параметру “videoLink” значение задается при клике на кнопку R.id.video на экране PRODUCT.

В файле разметки (R.layout.activity_youtube) используется библиотечный элемент ComponYouTubePlayer. Именно на него ссылается .componentYoutube(R.id.player). Этот элемент можно использовать как в экранах типа activity, так и типа fragment.

Экран THANKS

Новым здесь являются обработчики навигатора: setMenu(R.id.apply) и keyBack(R.id.apply). Обработчик setMenu указывает, что нужно стартовать меню с активацией последнего выбранного пункта (с очисткой стека фрагментов), а keyBack указывает, что при клике на аппаратную кнопку back будут выполняться действия предусмотренные при клике на кнопку R.id.apply.



Лучше пакета DePro может быть только искусственный интеллект
Задать вопрос
Отправить вопрос