Отправляет email-рассылки с помощью сервиса Sendsay

[prg] Как реализовать перемещение по структурным частям view в talkback при свайпах в android

Всех приветствую. Обычно,когда мы свайпаем влево или вправо,talkback
переходит на предыдущее или следующее view. Подскажите пожалуйста,можно
ли реализовать и если да,то как,чтобы при попытке перейти на следующее
или предыдущее view,я попадал бы на следующую или предыдущую часть
структурной единицы view. К примеру у меня в textView записана формула
a+b/c. Как мне реализовать поведение,чтобы когда фокус стоит на этом
view и я свайпаю вправо,talkback читал мне знаменатель,т.е c и чтобы
если я буду свайпать влево,talkback прочитал мне числитель a+b.
Естественно,где числитель и знаменатель и другие части в формуле,я буду
определять сам,просто мне нужна помощь в реализации этой идеи на уровне
android api,т.е как это реализовать,какое view мне лучше для этого
использовать - TextView или WebView и т.д. В общем я хочу реализовать
это так,как это делает mathjax и mathplayer с nvda,только с помощью того
же mathjax я могу перемещаться по структурным элементам формулы вроде
только стрелками,а я хочу реализовать эту возможность на сенсоре. Я
хотел посмотреть в сторону AccessibilityEvent,но когда я сделал тестовый
пример с onPopulateAccessibilityEvent,никакого события не
приходило,когда моё view теряло фокус. Конечно,можно использовать
onFocusChangeListener но тогда,наверное,если у пользователя включены
звуки talkback,он услышит звук перемещения фокуса на следующее view,а
потом он услышит этот же звук,поскольку фокус вернётся к текущему view.
В общем мне нужно как-то вклинится в процесс перед тем,как talkback
поймёт,что текущее view должно потерять фокус,при этом это должно
работать только при свайпах,а не в том случае,когда я нахожу другое view
ощупыванием экрана. Заранее всем огромное спасибо за помощь.

Ответить   Sun, 26 May 2019 00:43:08 +0300 (#3619561)

 

Ответы:

Приветствую всех!
Возможный вариант: реализовать для всех интересующих вас вложенных
элементов, как минимум, AccessibilityNodeInfo, если нужно, чтобы они стали
видимы для фокуса доступности. Можно проще -- оформить их в виде вложенных
View, тогда автоматически для них будет реализован системный вариант
AccessibilityNodeInfo. В любом случае, скорее всего, такие элементы будут
реагировать на ощупывание и вам придется написать свой обработчик
соответствующего события, чтобы скрыть его от TalkBack.

Возможные реализации (но, скорее всего, этим список вариантов не
ограничивается):
1. Написать свой полноценный MathView (если его еще никто не написал),
который будет содержать вложенные TextView с соответствующими частями
математических выражений. Тогда компоненты формулы будут доступны для
навигации TalkBack.
2. Посмотреть в сторону SpannableString. Есть пример, но он касается кликов
по отдельным словам в TextView
https://stackoverflow.com/questions/30349749/multiple-onclicklistener-on-each-word-of-string-in-text-view-android

Исходное сообщение Подскажите пожалуйста,можно

Ответить   "i_chay" Sun, 26 May 2019 14:20:35 +0300 (#3619576)

 

Здравствуйте Анатолий. Огромное спасибо Вам за ответ. Вы писали

Мне не понятно,как их вставлять внутрь view. Правильно ли я понимаю,что
для этого мне как раз нужно унаследоваться от класса view и
переопределить там какой-то метод,или можно использовать текущий метод
класса textview? Можно ли в этом случае скрывать вложенные
accessibilityNodeInfo,ведь я хочу реализовать возможность,чтобы эти view
и скрывались,т.е чтобы текст был снова в одном textview. Ещё Вы пишете

А вот этот вариант мне не нравится,поскольку тогда эти View увидят
зрячие,а им это для чтения формул не нужно. Можно,конечно,пошаманить с
цветами и другими свойствами View,чтобы они не были видны для зрячих,но
мне кажется всё же лучше и проще первый вариант. Только ещё вопрос,как
можно обрабатывать события клика на AccessibilityNodeInfo и узнать,по
какому именно accessibilityNodeInfo произошёл клик? Ещё Вы пишете

А вот это уже интересно,какие события мне нужно использовать,чтобы
скрыть view от talkback. Наверное Вы имеете ввиду класс
exploreByTouchhelper или отслеживание accessibilityEvent hover_enter и
hover_exit (типы событий могут быть написаны неточно). Есть ли примеры
реализации вложенных AccessibbilityNodeInfo и обработки ощупывания,чтобы
talkback не читал accessibilityNodeInfo/. Например,как реализовать
просто чтобы в TextView с текстом Мама мыла раму появлялись
accessibilityNodeInfo,доступные для talkback с текстами Мама,мыла,раму,а
если я кликну на accessibilityNodeInfo с текстом Мама - Дополнительно
Появлялись accessibilityNodeInfo с текстами М,а,м,а. При этом
AccessibilityNodeInfo более верхнего уровня должны скрываться,т.е Когда
я,к примеру,кликаю на accessibulityNodeInfo с текстом Мама,он должен
быть скрыт. Анологичная ситуация должна быть,к примеру при нажатии
кнопки назад,т.е если я к примеру нажму кнопку назад в
AccessibilityNodeInfo с текстом р,то это и остальные раскрытые
accessibilityNodeInfo,относящиеся к тексту раму,должны быть скрыты,а на
их месте должен появиться accessibilityNodeInfo с текстом раму. Пока я
писал всё это мне пришла мысль,что для решения моей проблемы наверно
придётся наследоваться от класса AccessibilityNodeInfo,чтобы отследить
событие accessibility_focused (тип события может быть написан
неправильно),чтобы понять,к примеру,по какому именно
AccessibilityNodeInfo я кликаю,или это можно сделать как-то по-другому?
Ещё Вы пишете

Как я понял из своих тестов под android,talkback и accessibility of math
content живут на разных планетах,если вообще не на разных
вселенных,поэтому я и думаю разработать такое приложение,чтобы хоть
как-то улучшить ситуацию. Ещё Вы пишете

Когда я мучался с ссылками в qsp,я тоже находил похожие варианты,но
когда я попадал на символ,используя детализацию по символам,у меня мой
код не работал поскольку,как Вы сами писали,talkback не перемещается по
фрагментам текста в textview. Заранее огромное Вам спасибо за помощь.

Ответить   Sun, 26 May 2019 15:55:58 +0300 (#3619582)

 

Приветствую всех!

Правильно. В принципе, все, что необходимо, изложено здесь:
https://developer.android.com/guide/topics/ui/accessibility/custom-views.html

На всякий случай напомню, что на поведение TalkBack влияют изменения двух
фокусов -- клавиатурного и доступности.
Физическое касание экрана приводит к тому, что фокус доступности
перемещается к View в точке касания, что порождает соответствующее
accessibility-событие, озвучиваемое TalkBack.
Тоже самое происходит с фокусом ввода, который перемещается в зависимости от
событий физического ввода, то есть от нажатий клавиш на клавиатуре и т.п.
Иными словами, пользователь в чистом виде не может сам управлять фокусом
доступности. Это делает либо непосредственно View, либо TalkBack,
интерпретируя клавиатурные или жестовые команды (например,
свайпы)соответствующим образом.
Схожий момент и с гранулярной навигацией по текстовому содержимому -- это
касается только TalkBack или других служб доступности.
SpannableString не работают с гранулярной навигацией по текстовому
содержимому. Они позволяют "связать" с определенным фрагментом текста ваш
объект и реализовать нужную логику, например, при касании этого фрагмента
текста. Предполагаемый вариант: по щелчку на соответствующем фрагменте ваш
View либо вызывает announceForAccessibility с нужным текстом, либо меняет
contentDescription (или и то, и другое одновременно).
Более детальные ответы на ваши вопросы требуют написания кода и,
соответственно, его проверки и т.п.
А это уже ваша работа.

Исходное сообщение > Правильно ли я понимаю,что

Ответить   "i_chay" Sun, 26 May 2019 19:17:59 +0300 (#3619587)

 

Здравствуйте Анатолий. Вы писали

https://developer.android.com/guide/topics/ui/accessibility/custom-views.html

Я понял,как добавлять свои вертуальные view,поскольку это было написано
в документации и там было указание на пример,в котором ещё один класс
наследуется от AccessibilityNodeProvider. Теперь возникает вопрос,как
реализовать добавление view при клике по родительскому view,чтобы оно
стало скрытым и на его месте появились дети,ведь в примере этот метод
срабатывает,если система хочет получить от view
AccessibilityNodeProvider,а мне нужно это сделать при клике по view или
по его детям. Также возникает вопрос,как вернуться на предыдущий
уровень,если,к примеру,я нажму кнопку назад. Можно,конечно,получить
AccessibilityNodeInfo от того view,на котором у меня был
фокус,затем,получив родителя,удалить всех детей кроме того,на котором у
меня стоял фокус,после чего сделать этого ребёнка родителем,но я не
уверен,что это правильный подход. Ещё мне непонятно,как получить View
(заголовок,формулу,параграф,ссылку и любой тег) у WebView и заменить его
моим костомным view (просто скорее всего у меня документ с формулами
будет в WebView,поскольку тогда незрячий пользователь сможет
осуществлять структурную навигацию по документу,т.е навигацию по
заголовкам,ссылкам и т.д). Также я прочитал,что вроде я могу
использовать onTouchEvent или onDispatchMotionEvent (названия событий
написаны неточно),но ведь эти события вроде некорректно работают с
talkback и для того,чтобы получить все Action,включая Action_Up,нужно
использовать класс ExploreByTouchHelper,об этом писали здесь.
<https://groups.google.com/d/msg/eyes-free-dev/xnYdzcnhUIM/gj_GneRPBAAJ>Но
в статье,на которую Вы мне дали ссылку написано,что делегаты нужно
использовать вроде до android 4.0,а с android 4.0 нужно переопределять
методы класса view. Ещё Вы пишете

Получается,что Вы предлагаете мне вернуться на тот вариант,который
изначально был сделан разработчиками quest player. они в
классе,унаследованном вроде от ScrollMovementMethod использовали событие
OntouchEvent,или похожее и определяли по координатам,на какую ссылку я
нажал,но для меня лично этим пользоваться было очень неудобно,и я очень
редко мог попадать на ссылки. К тому же при касании view talkback не
читает символа,который у меня под пальцами,а читает весь текст или
ContentDescription view,которого я касаюсь. А когда я мучился со
ссылками,не зная как сделать их доступными для нас,я вообще сломал и эту
возможность и только благодаря Вам я смог сделать ссылки в qsp
доступными для нас. Хотя я вроде видел TextView,в котором если
я,используя детализацию по символам,становлюсь на ссылку и кликаю на
неё,она открывается в клиенте,предназначенном для открытия ссылок такого
типа,но я не представляю,как это реализовать с exec ссылками в
qsp,поскольку сейчас можно открывать ссылки только используя угловые
жесты talkback и находя ссылку в списке ссылок,а вот если я кликаю ровно
на эту ссылку,то ничего не происходит. Вообще очень жаль,что вроде на
developer.android.com нету раздела или статьи,которая бы описывала,как
сделать ссылки кликабельными для незрячих и чтобы понять этот
секрет,нужно усердно читать исходники talkback. Поэтому Ваш пример с
ClickSpan показывает,как не нужно разрабатывать приложения,чтобы они
были полностью доступны для незрячих. Если я не прав,то поправьте меня
пожалуйста,просто единственный вариант,на мой взгляд,как кликать по
ClickSppan,это сделать виртуальную иерархию view. Кстати правильно ли я
понял,что этот вариант,на котором я пока что остановился,поможет
перемещаться по формуле не только с сенсора,но и с клавиатуры,ведь я по
сути перемещаюсь по view,хоть они и виртуальны? Заранее благодарю Вас за
помощь.

Ответить   Mon, 27 May 2019 14:49:38 +0300 (#3619675)

 

Приветствую всех!

Пару слов о виртуальной структуре, которую образуют AccessibilityNodeInfo.
Эта структура виртуальна, поскольку не представлена в GUI на экране, но
AccessibilityNodeInfo -- это не то же самое, что View.
У всех стандартных View есть реализация соответствующей структуры из
accessibility-узлов, поэтому, возможно, и возникает неверное представление,
что это одно и то же.

Если вы хотите добавить дочерний View, используйте ViewGroup.addView():
http://developer.alexanderklimov.ru/android/views/addview.php

Ваш MathView должен содержать поле, которое хранит текущее состояние
математической формулы(например, свернуто и развернуто) .
В зависимости от значения этого поля вы и формируете нужную структуру
accessibility-узлов.
Это поле меняет свое значение при щелчке и / или иных событиях, которые
приходят в ваш MathView.
Любой программируемый компонент в любом GUI -- это конечный автомат.

Использовать WebView, На мой взгляд, не очень удачная идея. Это большой и
самодостаточный компонент. Вряд ли вы сможете манипулировать его
содержимым. Кроме того, раньше WebView сам обеспечивал свою доступность при
помощи javascript.
А как сейчас, вы в курсе?

Чтобы View стал способен получать клавиатурный фокус, используйте
View.setFocusable().
И не смешивайте функционал своего кастомного View и службы доступности
(например, TalkBack).
Навигацию по AccessibilityNodeInfo осуществляет TalkBack и ваш View тут ни
при чем.
Ваш View должен реализовать дерево accessibility-узлов, соответствующее его
состоянию.
Свайпы TalkBack для вас, как разработчика кастомного View, вообще не
существуют.

Исходное сообщение возникает вопрос,как

[...]
меня документ с формулами

[...]

Ответить   "i_chay" Mon, 27 May 2019 21:27:57 +0300 (#3619709)

 

Здравствуйте Анатолий. Вы писали

Если честно,я раньше думал,что это почти одно и тоже,только классы у них
разные: View и AccessibilityNodeInfo. Ещё Вы пишете

Дело в том,что у меня идея заключается в том,чтобы реализовать
многоуровневую навигацию,как это сделано в mathjax,т.е можно сворачивать
и разворачивать части формулы,хотя для первого этапа Ваш вариант
подойдёт,но в дальнейшем мне всё равно придётся вернуться к
этому,поэтому для меня и важно знать,на каком узле в момент клика у меня
стоит фокус. Как я понял,я могу не наследоваться от класса
AccessibilityNodeProvider,поскольку мне нужно сворачивать структуру
только,к примеру,при нажатии кнопки назад,а разворачивать только при
клике на view,главное понять,как правильно получить
AccessibilityNodeInfo и установить его для view. Кстати всё же хотелось
бы уточнить,как более правильно возвращаться к предыдущему состоянию
узлов,т.е свернуть формулу или её часть. Ещё Вы пишете

Если честно нет,но хотелось бы узнать,как сейчас с этим обстоит
ситуация. Ещё Вы пишете

Я имел ввиду,что по дереву узлов я смогу перемещаться не только на
сенсоре,но и на клавиатуре.

Ответить   Mon, 27 May 2019 21:09:21 +0300 (#3619712)

 

Приветствую всех.

Поле состояния вашего MathView не обязательно должно быть плоским типом.
Это может быть поле определенного вами класса, который и будет содержать
более детальную информацию о состоянии MathView -- режим, уровень погружения
и т.п.
Это все-таки ООП, поэтому любая переменная всегда подразумевается как
объект, а не плоский тип.

Чтобы при помощи клавиатуры перемещаться по View, эти View должны
обозначитьс себя как способные получать клавиатурный фокус.
Что и делает метод setFocusable(). Это если речь идет, например, при
перемещении клавиатурного фокуса клавишами со стрелками (D-Pad).
Если вы имеете виду клавиатурные комбинации TalkBack, то опять у вас
путанница с тем, что происходит: по этим комбинациям TalkBack перемещается
по дереву accessibility-узлов, а реальный клавиатурный фокус при этом не
перемещается.

Ответить   "i_chay" Tue, 28 May 2019 15:45:42 +0300 (#3619795)

 

Здравствуйте Анатолий. Вы писали

Понятно. Кстати,а что нам даёт атрибут focusableInTouchMode? По поводу
клика я понял,что я могу получать accessibilityNodeInfo,которое я смогу
изменять,у View используя статический метод uptain,но я не могу
понять,как узнать,на каком узле у меня стоит фокус talkback,ведь я
должен знать,какой узел сворачивать и разворачивать. Также хотелось бы
узнать,кто теперь обеспечивает доступность WebView и можно ли всё таки
получить view у webView,такие как заголовки,ссылки и т.д. Заранее
благодарю Вас за помощь.

Ответить   Tue, 28 May 2019 17:21:57 +0300 (#3619797)

 

Приветствую всех!
По поводу focusableInTouchMode есть пояснения на сайте разработчиков:
https://developer.android.com/guide/topics/ui/ui-events?hl=ru

AccessibilityNodeInfo содержит методы findFocus и isAccessibilityFocused.
Это должно работать, как минимум в случаях, если вы базируетесь на системных
View, которые уже содержат реализацию структуры AccessibilityNodeInfo.
Но у вас есть поле, характеризующее состояние MathView. Можете хранить в
одном из его членов ссылку на актуальный AccessibilityNodeInfo, чтобы каждый
раз не перебирать все узлы.
Можете в том или ином виде хранить маршрут, проделанный пользователем по
математическому выражению.
Как вы его реализуете -- ваше дело, способов много.
можете сделать стек в который будете помещать строковый фрагмент формулы,
соответствующий текущему уровню погружения.

По поводу WebView не понял ваших формулировок. Хотите узнать -- изучайте
WebView, смотрите документацию, исходники, пишите тесты.

Ответить   "i_chay" Tue, 28 May 2019 22:58:14 +0300 (#3619824)

 

Здравствуйте Анатолий. Вы писали

А если я создаю костомный клас View,это будет работать? Ещё Вы пишете

Вопрос в том,как его правильно получить? Будет ли правильно использовать
метод класса accessibilityEbent.getRecord(),а потом использовать метод
getSource(),или есть более правильный подход? Если мой подход
правильный,то какой AccessibilityRecord по индексу мне нужно брать,чтобы
получить AccessibilityNodeInfo? Просто в примере в android sdk(api 18)
разработчики не отлавливали клик,а определяли актуальный
AccessibilityNodeInfo по координатам в ondispatchevent,а мне как раз
нужно получить сам узел,на котором сейчас находится talkback. Ещё Вы пишете

Я имел ввиду Ваше письмо,в котором Вы писали,знаю ли я как обстоит
сейчас дело с webview,поскольку сейчас,как я понял,javascript не
обеспечивает доступность webview. Заранее благодарю Вас за помощь.

Ответить   Tue, 28 May 2019 23:35:10 +0300 (#3619828)