Как то делал я один проект, в очередной раз как вы поняли. И заказчику понадобилось сделать вьюху, которая бы выглядела как пошаговая, знаете есть такие вьюхи типа вы пошагово выполняете какие-то действия, там авторизацию или регистрацию, так вот тут он захотел что бы такое было на создании одной инфы в приложении, вверху у нас есть эта пошаговая вьюха, а ниже у нас список с внесенными в него данными, в нашем случае я решил что это будут просто текстовые айтемы без какой либо логической нагрузки, так как по сути я хотел показать как я сделал связь между этой пошаговой вьюхой и списком.
Код особо не претендует на свою гениальность, я когда это писал, плакал как девочка ибо проект то написан именно таким макаром, и эти действия все можно в принципе реализовать немного иначе, даже с помощью того-же RecyclerView разделив его на две части, первая была бы горизонтальной вьюхой, а вторая была бы списком, но в моем случае я сделал отдельными вьюхами. Первая это кастомная вью с HorizontalScrollView, а вторая это ListView в которой я по ID отображаю нужный мне список данных. Данные же я хранить буду в БД которую я создам с помощью Realm. Про него я кстати уже писал, можете почитать статью, возможно окажется полезной…
Для начала давайте настроим проект перед стартом. Я буду использовать две библиотеки для созданния данного проекта, первая это Realm — для создания БД и вторая ButterKnife — для удобного подключения вьюх в проекте. Вот так будет выглядеть мой build.gradle:
build.gradle
Тут мы подключили зависимость для ButterKnife — com.neenbedankt.gradle.plugins:android-apt:1.8', а так он остается по сути такой же каким его создает Android Studio. Дальше у нас надо добавить библиотеки в app/build.gradle.
app/build.gradle
Мы добавили плагин для подключения библиотек через приставку apt — android-apt и потом аж в dependencies мы добавили три строчки для подключения Realm'a и ButterKnife.
Дальше давайте начнем создавать нашу пошаговую вьюху, для начала нам нужно создать вьюху с самими кнопками, которую мы будем создавать в нашем скролле, ее мы назовем ButtonView и в ней мы назначим все нужные параметры и стили нашим кнопкам.
Сперва покажу как будет выглядеть xml часть нашей вьюхи.
view_steps_button.xml
Здесь мы создали две кнопки, первая у нас видимая которая главная и которая побольше, вторая которая находится под ней, она невидимая и она соответственно меньшего размера. Еще у нас там есть полоска в три пикселя, она находится по центру вьюхи с сдвигом в -20 пикселей, что бы находится всегда по центру именно главной, большой кнопки, так как у нас вся вьюха строится вокруг именно ее.
Еще у нас к нашим кнопкам идет стиль что бы эти кнопки сделать круглыми. Вот он как выглядит.
round_button.xml
Здесь мы просто прописываем что кнопка у нас будет в форме овала, белого цвета
ButtonView.java
Здесь мы проинициализировали наши кнопки, создали пару стилей. Вот на пример в методе init() мы подключили ButterKnife и прицепили нашу вьюху. Дальше в методе setupView() мы задали стили для большой кнопки и для маленькой кнопке. Так же в этом классе мы проинициализировали еще кучу dimens которые нам нужны для изменения кнопок и текста на них и размера линий которые соединяют наши круглые кнопки, так как если мы не будем этого делать, то у нас постоянно будет дырка между ними.
А еще нам не хватает в файле dimens.xml наших настроек которые мы указали выше. Вот так он будет у нас выглядеть.
dimens.xml
Теперь нам нужно создать главную вьюху которая будет в себе содержать HorizontalScrollView в которую мы будем сетить нашу ButtonView.
Опять же, с начала я приведу код нашей разметки, а потом уже опишу работу функционала.
view_buttons_step.xml
Тут как видно все просто, у нас есть сам горизонтальный скролл и в нем пара LinearLayout'ов. В тот который имеет id — buttonsView мы будем сетить наш класс ButtonView. Думаю что вы заметили что мы используем кастомный HorizontalScrollView, в нем у нас тоже происходит некоторая магия, давайте покажу какая.
ObservableHorizontalScrollView.java
Для того что бы у нас наш scrollView умел отображать айтемы внутри скролла по центру, то есть что бы мы могли дотянуть самый крайний левый и самый крайний правый айтемы в центр scrollView, в обычном мы так сделать не сможем, по этому пришлось выпендриваться и добавлять по отступу по бокам с права и с лева. Это все происходит тут onPreDraw().
Так же у нас есть метод scrollToTheEnd() — его мы будем использовать для скролла тупо в самый конец scrollView.
scrollToView() — этот метод мы будем использовать для центрирования кликнутой вьюхи.
getDeepChildOffset() — просто метод который расчитывает координаты кликнутой вьюхи и передает их в scrollToView().
Дальше давайте посмотрим как будет выглядеть класс ButtonStepsView и я раздельно по методам раскажу как тут все работает.
ButtonStepsView.java
В шапке этого класса мы инициализиуем список, леяут в который будем сетить кнопки, создаем объект класса ButtonView и создаем несколько списков для сохранения состояний тех или иных вьюх.
В методе init() мы как всегда инициализируем ButterKnife и цепляем леяут к вьюхе.
addMainButton() — в этом методе мы создаем кнопку с ее параметрами, лисенарами и добавляем все это в списки для того что бы мы могли оперировать далее ими. По созданию кнопки мы делаем все кнопки маленькими, а ту которую создали мы делаем большой и вызываем метод скролла в самый конец scrollView().
addSubBtn() — его мы вызываем когда хотим сделать видимой саб кнопку которая у нас находится под главной кнопкой. И опять же, в ней мы делаем все кнопки маленького размера, а саб кнопку мы делаем большой.
onButtonClick() — метод который по клику делает все кнопки маленькими, а кликнутую мы делаем большой и переносим нас к ней по центру. Коллбек в конце метода обновляет список который мы будем отображать под вьюхой.
makeAllButtonsSmall() — общий метод который делает все кнопки маленькими, а нужную делает больше. Его мы вызываем постоянно когда нам нужно в вьюхе сделать кнопки меньше, а на определенной сконцентрировать и сделать ее больше.
setButtonsStyle() — метод который делает все кнопки маленькими, оба метода makeAllButtonsSmall() и setButtonsStyle() завязаны друг на друге.
Дальше у нас идут геттеры и сеттеры которые мы используем для получения номера шага и сета лисенера коллбека. Коллбек же умеет обновлять данные в адаптере и выводить нужные данные в него.
Дальше нам нужно создать фрагмент который у нас будет выступать главным экраном на котором у нас будет распологаться ButtonStepsView и ListView в котором мы будем отображать относящиеся к шагу айтемы.
Для начала давайте создадим активити в которую мы будем отображать фрагмент.
StepsActivity.java
Пока все довольно просто выглядит :) А еще у нас есть activity_steps в котором мы наш фрагмент указываем как default.
activity_steps.xml
Просто указываем в теге fragment что мы хотим что бы наш StepsFragment будет дефолтным и нам нужно в этой активити отображать только его.
Теперь рассмотрим разметку нашего фрагмента.
fragment_steps.xml
В ней находится ранее созданная нами ButtonStepsView, ListView и две кнопки. Для чего ButtonStepsView мы сюда цепляем это понятно, для чего ListView я думаю тоже. Две кнопки же нам нужны для создания отдельных шагов и айтемов в самске привязанном к шагу.
StepsFragment.java
В шапке класса у нас как всегда идет инициализация всех нужных переменных и констант. А вот методы я опишу что в них да как.
onViewCreated() — в нем мы создали нужные нам объекты адаптера, списка и вьюх и заодно создали первую кнопку которая у нас должна быть на экране.
onCreateView() — по старинке сетит леяут в фрагмент.
onNextClick() — отслеживает клик по кнопке Create step.
onAddClick() — добавляет каждый клик в наш ListView один айтем.
selectData() — создает адаптер и сетит в него данные.
onActivityResult() — как только возвращается какой-то результат оно в зависимости от того что вернула активити создает или главную кнопку или саб кнопку.
onUpdateAdapter() — метод который обнуляет адаптер когда создается новая кнопка.
Вот как то так обстоят дела в этом классе. Дальше нам нужно создать несколько классов, адаптер для списка айтемов, контроллер для работы с БД, несколько моделей для БД и активити которая будет создавать или главную кнопку или саб. кнопку.
Начнем мы с того что создадим адаптер для отображения айтемов. Он простой до ужаса.
StepsAdapter.java
В этот адаптер мы сетим данные из нашего контроллера, они у нас находятся в виде RealmResults. Если что этот формат можно переконвертировать в в ArrayList или в String[]. В общем в любой удобный вид. Далее мы в getView() сетим данные из этого RealmResult класса и выводим в текствью. А вот так будет выглядеть наш леяут для айтемов в адаптере.
item_steps.xml
Еще нам не хватает контроллера для БД. В нем у нас всего пара методов, для загрузки данных и выгрузки, нам этого хватит.
StepsController.java
В конструкторе мы проинициализировали Realm, задали конфиги и т.д. А дальше мы создали два метода, первый это addInfo() который записывает данные в БД. Второй это getInfo(), в нем мы вытаскиваем все данные из БД по ID и выводим в RealmResults. Еще есть методв getNextKey() но он нужен для того что бы в БД были уникальные айдишники, чисто для этого.
Еще нам нужен класс модель для БД, в нем у нас будет обозначен ID, Step ID и имя, самое важное для нас.
StepsDataModel.java
Этот класс мы унаследовали от RealmObject для того что бы этот класс использовался как таблица БД в Realm.
Ну и теперь все что нам осталось это создать класс который будет давать выбор что создавать, шаг или подшаг собственно главную кнопку или саб кнопку.
CreateStepActivity.java
Проинициализировав леяут и ButterKnife в onCreate() мы сказали что будем юзать ButterKnife. А дальше в onSectionClick() мы выбираем что создает новую главную кнопку, а в методе onSubClick() мы создаем саб. кнопку.
Ну и теперь леяут.
activity_check_step.xml
Тут мы создали две кнопки, по нажатию на одну мы создаем главную кнопку, по нажатию на вторую создаем саб. Картинки к кнопкам можете найти ниже.
А вот так будет выглядеть наш string.xml.
string.xml
Пробуем, компилируем после этого и смотрим работает ли. Все должно скомпилироваться и вы должны увидеть то же самое что я привел выше на скриншотах. Ну если что-то не сложилось, то всегда есть исходники :) С ними должно сто процентов заработать все. Главное не забыть прописать активити в AndroidManifest. А то будет падать. Может быть когда-нибудь дойдут руки переписать на лучший лад, а пока вот так...
Исходники:
GitHub
Код особо не претендует на свою гениальность, я когда это писал, плакал как девочка ибо проект то написан именно таким макаром, и эти действия все можно в принципе реализовать немного иначе, даже с помощью того-же RecyclerView разделив его на две части, первая была бы горизонтальной вьюхой, а вторая была бы списком, но в моем случае я сделал отдельными вьюхами. Первая это кастомная вью с HorizontalScrollView, а вторая это ListView в которой я по ID отображаю нужный мне список данных. Данные же я хранить буду в БД которую я создам с помощью Realm. Про него я кстати уже писал, можете почитать статью, возможно окажется полезной…
Для начала давайте настроим проект перед стартом. Я буду использовать две библиотеки для созданния данного проекта, первая это Realm — для создания БД и вторая ButterKnife — для удобного подключения вьюх в проекте. Вот так будет выглядеть мой build.gradle:
build.gradle
Тут мы подключили зависимость для ButterKnife — com.neenbedankt.gradle.plugins:android-apt:1.8', а так он остается по сути такой же каким его создает Android Studio. Дальше у нас надо добавить библиотеки в app/build.gradle.
app/build.gradle
Мы добавили плагин для подключения библиотек через приставку apt — android-apt и потом аж в dependencies мы добавили три строчки для подключения Realm'a и ButterKnife.
Дальше давайте начнем создавать нашу пошаговую вьюху, для начала нам нужно создать вьюху с самими кнопками, которую мы будем создавать в нашем скролле, ее мы назовем ButtonView и в ней мы назначим все нужные параметры и стили нашим кнопкам.
Сперва покажу как будет выглядеть xml часть нашей вьюхи.
view_steps_button.xml
Здесь мы создали две кнопки, первая у нас видимая которая главная и которая побольше, вторая которая находится под ней, она невидимая и она соответственно меньшего размера. Еще у нас там есть полоска в три пикселя, она находится по центру вьюхи с сдвигом в -20 пикселей, что бы находится всегда по центру именно главной, большой кнопки, так как у нас вся вьюха строится вокруг именно ее.
Еще у нас к нашим кнопкам идет стиль что бы эти кнопки сделать круглыми. Вот он как выглядит.
round_button.xml
Здесь мы просто прописываем что кнопка у нас будет в форме овала, белого цвета
ButtonView.java
Здесь мы проинициализировали наши кнопки, создали пару стилей. Вот на пример в методе init() мы подключили ButterKnife и прицепили нашу вьюху. Дальше в методе setupView() мы задали стили для большой кнопки и для маленькой кнопке. Так же в этом классе мы проинициализировали еще кучу dimens которые нам нужны для изменения кнопок и текста на них и размера линий которые соединяют наши круглые кнопки, так как если мы не будем этого делать, то у нас постоянно будет дырка между ними.
А еще нам не хватает в файле dimens.xml наших настроек которые мы указали выше. Вот так он будет у нас выглядеть.
dimens.xml
Теперь нам нужно создать главную вьюху которая будет в себе содержать HorizontalScrollView в которую мы будем сетить нашу ButtonView.
Опять же, с начала я приведу код нашей разметки, а потом уже опишу работу функционала.
view_buttons_step.xml
Тут как видно все просто, у нас есть сам горизонтальный скролл и в нем пара LinearLayout'ов. В тот который имеет id — buttonsView мы будем сетить наш класс ButtonView. Думаю что вы заметили что мы используем кастомный HorizontalScrollView, в нем у нас тоже происходит некоторая магия, давайте покажу какая.
ObservableHorizontalScrollView.java
Для того что бы у нас наш scrollView умел отображать айтемы внутри скролла по центру, то есть что бы мы могли дотянуть самый крайний левый и самый крайний правый айтемы в центр scrollView, в обычном мы так сделать не сможем, по этому пришлось выпендриваться и добавлять по отступу по бокам с права и с лева. Это все происходит тут onPreDraw().
Так же у нас есть метод scrollToTheEnd() — его мы будем использовать для скролла тупо в самый конец scrollView.
scrollToView() — этот метод мы будем использовать для центрирования кликнутой вьюхи.
getDeepChildOffset() — просто метод который расчитывает координаты кликнутой вьюхи и передает их в scrollToView().
Дальше давайте посмотрим как будет выглядеть класс ButtonStepsView и я раздельно по методам раскажу как тут все работает.
ButtonStepsView.java
В шапке этого класса мы инициализиуем список, леяут в который будем сетить кнопки, создаем объект класса ButtonView и создаем несколько списков для сохранения состояний тех или иных вьюх.
В методе init() мы как всегда инициализируем ButterKnife и цепляем леяут к вьюхе.
addMainButton() — в этом методе мы создаем кнопку с ее параметрами, лисенарами и добавляем все это в списки для того что бы мы могли оперировать далее ими. По созданию кнопки мы делаем все кнопки маленькими, а ту которую создали мы делаем большой и вызываем метод скролла в самый конец scrollView().
addSubBtn() — его мы вызываем когда хотим сделать видимой саб кнопку которая у нас находится под главной кнопкой. И опять же, в ней мы делаем все кнопки маленького размера, а саб кнопку мы делаем большой.
onButtonClick() — метод который по клику делает все кнопки маленькими, а кликнутую мы делаем большой и переносим нас к ней по центру. Коллбек в конце метода обновляет список который мы будем отображать под вьюхой.
makeAllButtonsSmall() — общий метод который делает все кнопки маленькими, а нужную делает больше. Его мы вызываем постоянно когда нам нужно в вьюхе сделать кнопки меньше, а на определенной сконцентрировать и сделать ее больше.
setButtonsStyle() — метод который делает все кнопки маленькими, оба метода makeAllButtonsSmall() и setButtonsStyle() завязаны друг на друге.
Дальше у нас идут геттеры и сеттеры которые мы используем для получения номера шага и сета лисенера коллбека. Коллбек же умеет обновлять данные в адаптере и выводить нужные данные в него.
Дальше нам нужно создать фрагмент который у нас будет выступать главным экраном на котором у нас будет распологаться ButtonStepsView и ListView в котором мы будем отображать относящиеся к шагу айтемы.
Для начала давайте создадим активити в которую мы будем отображать фрагмент.
StepsActivity.java
Пока все довольно просто выглядит :) А еще у нас есть activity_steps в котором мы наш фрагмент указываем как default.
activity_steps.xml
Просто указываем в теге fragment что мы хотим что бы наш StepsFragment будет дефолтным и нам нужно в этой активити отображать только его.
Теперь рассмотрим разметку нашего фрагмента.
fragment_steps.xml
В ней находится ранее созданная нами ButtonStepsView, ListView и две кнопки. Для чего ButtonStepsView мы сюда цепляем это понятно, для чего ListView я думаю тоже. Две кнопки же нам нужны для создания отдельных шагов и айтемов в самске привязанном к шагу.
StepsFragment.java
В шапке класса у нас как всегда идет инициализация всех нужных переменных и констант. А вот методы я опишу что в них да как.
onViewCreated() — в нем мы создали нужные нам объекты адаптера, списка и вьюх и заодно создали первую кнопку которая у нас должна быть на экране.
onCreateView() — по старинке сетит леяут в фрагмент.
onNextClick() — отслеживает клик по кнопке Create step.
onAddClick() — добавляет каждый клик в наш ListView один айтем.
selectData() — создает адаптер и сетит в него данные.
onActivityResult() — как только возвращается какой-то результат оно в зависимости от того что вернула активити создает или главную кнопку или саб кнопку.
onUpdateAdapter() — метод который обнуляет адаптер когда создается новая кнопка.
Вот как то так обстоят дела в этом классе. Дальше нам нужно создать несколько классов, адаптер для списка айтемов, контроллер для работы с БД, несколько моделей для БД и активити которая будет создавать или главную кнопку или саб. кнопку.
Начнем мы с того что создадим адаптер для отображения айтемов. Он простой до ужаса.
StepsAdapter.java
В этот адаптер мы сетим данные из нашего контроллера, они у нас находятся в виде RealmResults. Если что этот формат можно переконвертировать в в ArrayList или в String[]. В общем в любой удобный вид. Далее мы в getView() сетим данные из этого RealmResult класса и выводим в текствью. А вот так будет выглядеть наш леяут для айтемов в адаптере.
item_steps.xml
Еще нам не хватает контроллера для БД. В нем у нас всего пара методов, для загрузки данных и выгрузки, нам этого хватит.
StepsController.java
В конструкторе мы проинициализировали Realm, задали конфиги и т.д. А дальше мы создали два метода, первый это addInfo() который записывает данные в БД. Второй это getInfo(), в нем мы вытаскиваем все данные из БД по ID и выводим в RealmResults. Еще есть методв getNextKey() но он нужен для того что бы в БД были уникальные айдишники, чисто для этого.
Еще нам нужен класс модель для БД, в нем у нас будет обозначен ID, Step ID и имя, самое важное для нас.
StepsDataModel.java
Этот класс мы унаследовали от RealmObject для того что бы этот класс использовался как таблица БД в Realm.
Ну и теперь все что нам осталось это создать класс который будет давать выбор что создавать, шаг или подшаг собственно главную кнопку или саб кнопку.
CreateStepActivity.java
Проинициализировав леяут и ButterKnife в onCreate() мы сказали что будем юзать ButterKnife. А дальше в onSectionClick() мы выбираем что создает новую главную кнопку, а в методе onSubClick() мы создаем саб. кнопку.
Ну и теперь леяут.
activity_check_step.xml
Тут мы создали две кнопки, по нажатию на одну мы создаем главную кнопку, по нажатию на вторую создаем саб. Картинки к кнопкам можете найти ниже.
А вот так будет выглядеть наш string.xml.
string.xml
Пробуем, компилируем после этого и смотрим работает ли. Все должно скомпилироваться и вы должны увидеть то же самое что я привел выше на скриншотах. Ну если что-то не сложилось, то всегда есть исходники :) С ними должно сто процентов заработать все. Главное не забыть прописать активити в AndroidManifest. А то будет падать. Может быть когда-нибудь дойдут руки переписать на лучший лад, а пока вот так...
Исходники:
GitHub
Комментариев нет:
Отправить комментарий