- How to add Extended Floating Action Button in Android | Android Studio | Java
- Step 1: add the dependency
- Step 2: add the drawable files
- Step 3: design the XML file
- Step 4: add the functionality
- Android Accessibility — Resolving common Talkback issues
- Combining views into groups
- Example
- Solution
- XML layout snippet
- Action descriptions
- Example
- Solution
- Code snippet
- Roles
- Example
- Code snippet
- Updating information after state changes
- Example
- Solution
- Code snippet
- RecyclerView scrolling
- Example
- Layout snippet
- RecyclerView focus
- Example
- Code snippet
- Conclusions
- Реализация списка с заголовком, футером и пагинацией в Андроид
- RecyclerView
- Настройка Gradle
- Добавление RecyclerView в XML представление
- Привязка XML с классом JAVA
- RecyclerView ItemDecoration
- RecyclerView Adapter
- Пагинация
- Navigation Component-дзюцу, vol. 1 — BottomNavigationView
- Disclaimer
- Кейсы с BottomNavigationView
- Первый опыт
- Пора запускать приложение
- У нас есть workaround
- Адаптация workaround-а для фрагментов
- Выводы по работе с BottomNavigationView
How to add Extended Floating Action Button in Android | Android Studio | Java
How to add Extended Floating Action Button in Android | Android Studio | Java.
In this tutorial, we are going to create an extended floating action button in android. A floating action button (FAB) performs the primary, or most common, action on a screen. It appears in front of all screen content, typically as a circular shape with an icon in its center.
Extended Floating Action Button is the newly introduced class with Material Components library in Android.
Material Components is introduced with SDK 28 or Android P. It’s a superset of Support Design Library with lots of new additions and improvements. And, in this tutorial, we are going to create an extended floating action button.
So, let’s start creating the extended FAB.
Before going to create let’s see what you’re going to see.
Step 1: add the dependency
make sure to add the material design dependency in your build.gradle app file.
Step 2: add the drawable files
before going to design the main XML file, first, import the drawable files. Below drawable files that I used in my project.
Step 3: design the XML file
now, design the main XML file, add the Extended Floating Action Button that is set as the parent FAB and also add the child FAB. Here as a child FAB, I used two FABs.
parent FAB: Action
child FAB 1: Alarm
child FAB 2: Person
Step 4: add the functionality
now in the main JAVA file add the functionality for the extended FAB and add the click listener in the child FAB.
Источник
Android Accessibility — Resolving common Talkback issues
Many Android applications suffer from similar Talkback issues and at Microsoft To Do we run into these often as well. We use multiple strategies to make our app more accessible. This article covers a few scenarios where Talkback experience is improved.
A companion Github repository containing the sample code is available here. You can check it out and try running the demo app on your device to experience the issues and try the solutions yourself.
Combining views into groups
Not everything visible on the screen is meaningful; some views are used only for decoration, some images illustrate the text without adding additional information, and sometimes multiple views convey the meaning together but do not make sense separately. In these cases, the views can be combined to allow Talkback user to quickly navigate entire view, rather than having to skip through multiple different elements.
Example
Talkback reads the user element on the page as “User placeholder avatar”, “Name”, and then “Surname”. Each element can be navigated individually. The user icon is a placeholder which does not provide additional information. It takes three swipes to navigate through the element.
Solution
Content description is set on the entire group so Talkback reads only one label, containing all user information as “Name Surname”. Now navigation is done in only one swipe.
XML layout snippet
Content description is set on LinearLayout, child views are marked as not important for accessibility individually.
Action descriptions
As Talkback navigates the elements with click actions, the announcement generated will include some information, for example “Login, Button, Double tap to activate”. However, relying on default announcements is not always enough.
Example
A button with two actions generates an accessibility announcement of “Edit note, Double tap to activate, Double tap and hold to long press”.
Solution
Actions are modified to announce “Double tap to edit note, Double tap and hold to copy note”.
Code snippet
Custom actions are added in accessibility delegate, ensuring that it’s clear what happens when each action is carried out.
Roles
Talkback reads the element roles, such as Button, Switch, Checkbox, etc. This gets complicated when non-standard elements are used. For example, adding a click listener will add an action to Talkback announcement, but the role will generally not change, potentially causing confusion.
Example
The button is announced as “Login, Button”. Adding on a click listener to TextView does not include the “Button” announcement. In the last example, TextView is announced as “Button”.
Code snippet
Role is added by including it in the accessibility delegate. This is not an ideal solution; best practice is to use elements as intended, so using Button when Button behaviour is needed, which avoids the need to modify roles manually, as it is easy to miss some behaviour which comes by default. However, in some cases, this will help.
Updating information after state changes
Lint warning often reminds us about adding initial content descriptions, but for the elements with states, this might not be enough. It is important to remember to update accessibility information as well.
Example
The favorite button is not updated after the user taps on it, so the Talkback announcement still reads “Not favorite item, Button, Double tap to activate” after the user already added the item to favorites and the UI is updated to reflect this.
Solution
Favorite button content and action descriptions are updated so Talkback reads one of two states: “Not favorite item, Button, Double tap to add to favorites” and “Favorite item, Button, Double-tap to remove from favorites”.
Code snippet
When a tap event is received and the element state changes, the content and action descriptions are updated to reflect the current state of the item. This is especially important for elements which represent On/Off state, like the favorite button. Alternatively, an element which already supports On/Off states could be used in this scenario, like Switch or Checkbox. On the other hand, if more than two states are available, then custom elements make sense.
RecyclerView scrolling
If RecyclerView does not automatically scroll with Talkback navigation, it will make it very hard for Talkback users to know that there are more elements available. There is one common issue which usually causes this.
Example
The first RecyclerView allows user to see the first 5 elements and then navigation skips the rest. The second RecyclerView moves to the 6th element in the list and scrolls down to make additional elements available. The focus only moves away from RecyclerView when all elements are visited.
Layout snippet
If the following line is in the RecyclerView layout, removing it will fix the issue. It will also add additional in/out of list announcements to help the users navigate.
RecyclerView focus
As is the nature of RecyclerView, it can recycle the view holders if there are changes to the data. However, this can create focus issues if some view is no longer displayed or the view holder is reused in a different position. Understanding what is happening will help with keeping the focus unchanged.
Example
RecyclerViews allow the user to mark elements as deleted. In the first RecyclerView, once the delete icon is tapped and the element text is replaced with “Deleted ”, the focus returns to the top of the activity, so the user needs to navigate through the entire screen again to return to the original focus position. The second RecyclerView keeps the focus on the same element, shifting it from the icon to the name.
Code snippet
After the element is marked as deleted there is a short delay to allow RecyclerView time to reuse ViewHolders, then the desired position is found and focus is returned to that position. If the underlying data set is not changed and there is no refresh of the data in RecyclerView adapter, this could potentially be solved within ViewHolder itself. As always, the best solution is the one which addresses the specific need.
Conclusions
Accessibility is important for our team at Microsoft To Do. We spend a lot of time making sure every user can stay organised and accomplish more, independent of how they use their device. Most of our Android app releases include several accessibility improvements. We also work with our design team to consider accessibility requirements from the start.
Accessibility issues we encounter range from simple to tricky — it takes time and dedication to find and resolve them all. I hope this article helps you to solve some. Code snippets in the article have been simplified for clarity, so check the sample code for full implementations.
Is there a different way you would approach some of these? Let’s discuss it!
Источник
Реализация списка с заголовком, футером и пагинацией в Андроид
RecyclerView
RecyclerView — это расширенная версия ListView с некоторыми улучшениями в производительности и с новыми функциями. Как следует из названия, RecyclerView перерабатывает или повторно использует представления элементов при прокрутке. В RecyclerView гораздо проще добавлять анимации по сравнению с ListView. В этом уроке мы разберем, как создать RecyclerView с заголовком, футером, разбиением на страницы и анимацией.
Настройка Gradle
Добавьте следующую зависимость в файл build.gradle:
Добавление RecyclerView в XML представление
После того, как проект будет синхронизирован, добавьте компонент RecyclerView в ваш макет:
Привязка XML с классом JAVA
Теперь в методе onCreate вашей активности добавьте следующий код:
Прежде чем идти дальше, давайте подробно рассмотрим приведенный выше код
- Layout Manager — Простыми словами, Layout Manager помогает нам определить структуру нашего RecyclerView. Есть три встроенных Layout Managers. Помимо этого, мы можем создать собственный пользовательский Layout Manager, чтобы удовлетворить наши требования.
- LinearLayoutManager показывает элементы в списке с вертикальной или горизонтальной прокруткой.
- GridLayoutManager показывает элементы в сетке.
- StaggeredGridLayoutManager показывает элементы в шахматной сетке.
RecyclerView ItemDecoration
ItemDecoration позволяет приложению добавлять специальный полосы и смещения к определенным представлениям элементов из набора данных адаптера. Это может быть полезно для рисования разделителей между элементами, выделениями, границами визуальной группировки и т. д. – developer.android.com
В этом примере мы будем использовать ItemDecoration для добавления отступов к каждому элементу.
В вышеприведенном классе мы устанавливаем отступы к нулевому элементу.
RecyclerView Adapter
Теперь давайте настроим адаптер ReeyclerView с заголовком и футером.
Пагинация
Теперь, когда адаптер готов, давайте посмотрим, как добавить пагинацию в список RecyclerView. Это довольно легко сделать и должно быть добавлено в onCreate после установки Adapter to Recycler-View.
Всякий раз, когда данные изменяются в mList, вызывайте функцию ниже, чтобы обновить адаптер RecyclerView и показать новые данные.
Надеюсь, что этот пост поможет вам получить общее представление о настройке RecyclerView с заголовком, подвалом и пагинацией.
Источник
Navigation Component-дзюцу, vol. 1 — BottomNavigationView
Два года назад на Google I/O Android-разработчикам представили новое решение для навигации в приложениях — библиотеку Jetpack Navigation Component . Про маленькие приложения уже было сказано достаточно, а вот о том, с какими проблемами можно столкнуться при переводе большого приложения на Navigation Component , информации практически нет.
В этой и следующих двух статьях я расскажу о кейсах, с которыми может встретиться разработчик, желающий опробовать Navigation Component в большом Android-приложении.
UPDATE 30.12.2020:
Выводы, сделанные в этой статье, некорректны, так как при настройке BottomNavigationView была допущена серьёзная ошибка, которая повлекла за собой все описанные в статье проблемы. Подробности — в последней статье цикла.
Это текстовая версия моего выступления в рамках серии митапов по Android 11 в Android Academy. Само выступление было на английском, статью пишу на русском. Кому удобнее смотреть – велкам.
В первой статье я расскажу о кейсах, связанных с BottomNavigationView , во второй – о кейсах с вложенными графами навигации, в третьей – про навигацию в многомодульных приложениях, дип линки, встраиваемые фрагменты и диалоги. Все три статьи — лонгриды, которые, однако, способны сэкономить много времени и вам, и вашей команде.
Disclaimer
Я сделал пример, по структуре навигации повторяющий основные моменты навигации соискательского приложения hh.ru, и выхватил ряд проблем, о которых и собираюсь рассказать. Я основательно поресёрчил практическую сторону вопроса, но, разумеется, рассмотрел далеко не все возможные кейсы.
Схема моего тестового приложения выглядит так:
В цикле статей мы разберём каждый переход, который описан на этой схеме, а также несколько кейсов, которые не поместились на картинку.
Кейсы с BottomNavigationView
Когда я только-только услышал про Navigation Component , мне стало интересно: как будет работать BottomNavigationView и как Google подружит несколько отдельных back stack-ов в разных вкладках. Два года назад с этим кейсом были некоторые проблемы, и я решил проверить, как там обстоят дела сегодня.
Если кратко — проблемы не пропали, но появился способ их обойти. И, поскольку нижняя навигация сейчас есть практически в каждом большом приложении, нужно разбираться.
Первый опыт
Я установил Android Studio 4.1 Beta (последнюю более-менее стабильную версию на тот момент) и попробовал шаблон приложения с нижней навигацией. Начало было многообещающим.
- Мне сгенерировали Activity в качестве контейнера для хоста навигации и нижней навигации
Я убрал «шумовые» атрибуты, чтобы было проще читать.
Стандартный ConstraintLayout , в который добавили BottomNavigationView и тэг для инициализации NavHostFragment -а ( Android Studio , кстати, подсвечивает, что вместо фрагмента лучше использовать FragmentContainerView ).
- Для каждой вкладки BottomNavigationView был создан отдельный фрагмент
Все фрагменты были добавлены в качестве отдельных destination-ов в общий граф навигации.
- А ещё в проект был добавлен файл-ресурс для описания меню BottomNavigationView
При этом я заметил, что идентификаторы элементов меню должны совпадать с идентификаторами destination-ов в графе навигации. Не самая очевидная связь между табами BottomNavigationView и фрагментами, но работаем с тем, что есть.
Пора запускать приложение
После создания приложения из шаблона я запустил его и сразу столкнулся с двумя проблемами.
Первая проблема: при переключении между вкладками их состояние не сохранялось.
Для проверки я добавил во вкладку Dashboard простенькую ViewModel со счётчиком. На гифке видно, как я переключаюсь со вкладки Home на вкладку Dashboard , увеличиваю счётчик до четырёх. После этого я переключился обратно на вкладку Home и вновь вернулся на Dashboard . Счётчик сбросился.
Баг с описанием этой проблемы уже два года висит в Issue Tracker-е. Чтобы решить её, Google-у потребовалось серьёзно переработать внутренности фреймворка Fragment -ов, чтобы поддержать возможность работать с несколькими back stack-ами одному FragmentManager -у. Недавно на Medium вышла статья Ian Lake, в которой он рассказывает, что Google серьёзно продвинулись в этом вопросе, так что, возможно, фикс проблемы с BottomNavigationView не за горами.
Вторая проблема – следствие первой. По принятым принципам навигации, когда вы нажимаете на уже выбранную вкладку BottomNavigationView, вы должны вернуться на первый фрагмент в стеке текущей вкладки. Но когда это происходит, состояние этого первого фрагмента сбрасывается, так как сам фрагмент пересоздаётся.
Для демонстрации этой проблемы я добавил на вкладку Dashboard кнопку, которая ведёт на следующий экран. На гифке видно, как я переключаюсь на вкладку Dashboard , увеличиваю счётчик до трёх, а затем перехожу на экран Graphic . Если я нажимаю на кнопку Back – то всё работает как надо, состояние вкладки не сбрасывается. Но если, находясь на экране Graphic , я ещё раз нажму на вкладку Dashboard , то после возврата на первый экран в стеке увижу, что его состояние сброшено.
«Не самое лучшее первое впечатление», – подумал я. И начал искать фикс.
У нас есть workaround
Решение этих проблем живёт в специальном репозитории Google-а с примерами работы с Architecture Components , в проекте NavigationAdvancedSample.
Большая часть фикса расположена в файле NavigationExtensions.kt. В самом проекте довольно много кода, поэтому я не буду его разбирать подробно, а вместо этого подсвечу основные моменты, которые относятся к решению проблем.
- Во-первых, для каждой вкладки вводится отдельный, независимый граф навигации
Соответственно, для примера BottomNavigationView с тремя вкладками у нас получится три отдельных файла навигации XML, в которых в качестве startDestination будут указаны первые фрагменты вкладок.
- Во-вторых, для каждой вкладки под капотом создаётся отдельный NavHostFragment , который будет связан с графом навигации этой вкладки
FragmentManager пока что не поддерживает работу с множеством back stack-ов одновременно, поэтому пришлось придумать альтернативное решение, которое позволило ассоциировать с каждым графом свой back stack. Им стало создание отдельного NavHostFragment -а для каждого графа. Из этого следует, что с каждой вкладкой BottomNavigationView у нас будет связан отдельный NavController .
- В-третьих, мы устанавливаем в BottomNavigationView специальный listener , который будет заниматься переключением между back stack-ами фрагментов
В прикреплённом кусочке кода мы видим, как при переключении между вкладками BottomNavigationView выполняется специальная транзакция в FragmentManager -е, которая прикрепляет фрагмент выбранной вкладки и отцепляет все остальные фрагменты. По сути, так мы и переключаемся между различными back stack-ами.
- В итоге метод настройки BottomNavigationView возвращает разработчику специальную LiveData , которая содержит в себе NavController выбранной вкладки. Этот NavController можно использовать, например, для обновления надписи на ActionBar -е
Метод для настройки BottomNavigationView вызывают в onCreate -е, когда Activity создаётся в первый раз, затем в методе onRestoreInstanceState , когда Activity пересоздаётся с помощью сохранённого состояния.
Кроме того, для работы фикса нужно, чтобы идентификаторы элементов меню, которое используется для инициализации табов BottomNavigationView , совпадали с идентификаторами графов навигации.
Опять же, не самая очевидная связь между этими элементами, зато работает.
После применения этого workaround-а первые две проблемы исчезли – теперь состояние вкладки сохраняется между переключениями вкладок.
Первая проблема решилась:
Адаптация workaround-а для фрагментов
Очень здорово, что workaround помог решить основную проблему с сохранением состояний, но этих фиксов мне было недостаточно. Пример из проекта NavigationAdvancedSample использовал в качестве контейнера нижней навигации Activity, мне же нужен был фрагмент.
Посмотрите внимательно на эту схему:
На ней можно увидеть, что пользователь начинает свой путь в приложении со Splash-экрана:
Google говорит, что Splash-экраны – зло, ухудшающее UX приложения. Тем не менее, Splash-экраны – суровая реальность большинства крупных Android-приложений. И если мы хотим использовать в нашем приложении Single Activity -архитектуру, то в качестве контейнера нижней навигации придётся использовать Fragment , а не Activity :
Я добавил вёрстку для фрагмента с нижней навигацией и перенёс настройку BottomNavigationView во фрагмент:
Я добавил в свой пример Splash-экран и дополнительную вкладку для BottomNavigationView . А чтобы пример стал ещё более походить на приложение для соискателей hh.ru, я также убрал из него ActionBar .
Для этого я поменял тему приложения с Theme.MaterialComponents.DayNight.DarkActionBar на Theme.MaterialComponents.DayNight.NoActionBar и убрал код для связки NavController -а с ActionBar -ом:
После всех манипуляций я включил режим Don’t keep activities, запустил свой пример и… получил краш при сворачивании приложения.
На гифке видно, как я запустил приложение, и после Splash-экрана показывается экран с нижней навигацией. После этого мы сворачиваем приложение и получаем краш.
В чём была причина? При вызове onDestroyView активный NavHostFragment пытается отвязаться от NavController -а. Так как мой фрагмент-контейнер с нижней навигацией никак не привязывал к себе NavController , который он получил из LiveData , метод Navigation.findNavController из onDestroyView крашил приложение.
Добавляем привязку NavController -а к фрагменту с нижней навигацией (для этого в Navigation Component-е есть утилитный метод Navigation.setViewNavController ), и проблема исчезает.
Но это ещё не всё. Не выключая режим Don’t keep activities, я попробовал свернуть, а затем развернуть приложение. Оно снова упало, но с другим неприятным исключением – IllegalStateException в FragmentManager – FragmentManager already executing transactions .
На гифке видно, как мы сворачиваем приложение, находясь на экране с нижней навигацией, затем пытаемся развернуть приложение обратно и получаем краш.
Краш происходит в методах, которые прикрепляют NavHostFragment к FragmentManager -у после их создания. Это исключение можно исправить при помощи костыля: обернуть методы attach-detach в Handler.post <> .
После добавления Handler.post приложение заработало, как надо.
Выводы по работе с BottomNavigationView
На этом с BottomNavigationView всё, на следующей неделе расскажу про кейсы с вложенными графами навигации.
Источник