- Контекстное меню и подменю
- Программное создание контекстного меню
- Контекстное меню через ресурсы
- Полный список
- Русские Блоги
- Долгое нажатие Android Edittext не вызывает контекстное меню
- Краткое описание проблемы
- анализ
- решение
- Floating toolbar for text selection в Android Marshmallow: разбор нововведения
- Старое
- Первое. Меню вульгарис
- Второе. Контекстное меню
- Третье. Меню в AppBar и Toolbar
- Четвертое. Режим контекстных действий (Contextual action mode)
- Новое
- Пятое. Еще одно контекстное меню
- Шестое. Расширение меню при выделении текста
- Реализация
- Ой. Куда делось мое меню?
- Куда опять делось мое меню?
- Как разместить свой пункт перед стандартными?
- Странности в документации
Контекстное меню и подменю
Кроме стандартного меню в Android используется также контекстное меню, вызываемое при нажатии на объект в течение двух-трёх секунд (событие long-press). Также на некоторых моделях устройств контекстное меню можно вызвать при нажатии трекбола или средней кнопки манипулятора D-pad. В отличие от обычного меню, в контекстном меню не поддерживаются значки и быстрые клавиши. Второе важно отличие — контекстное меню применимо к компоненту, а меню к активности. Поэтому в приложении может быть одно меню и несколько контекстных меню, например, у каждого элемента TextView.
Программное создание контекстного меню
Для создания контекстного меню используется метод обратного вызова onCreateContextMenu(). В данный метод можно добавлять пункты меню при помощи методов add(). C помощью метода onContextItemSelected() можно обрабатывать выбор пункта. Но сначала надо зарегистрировать контекстное меню для нужного объекта, например, для TextView при помощи метода registerForContextMenu().
Если запустить проект, то уже сейчас можно увидеть контекстное меню, которое пока не будет реагировать на выбранные пункты меню.
Допишем код для выбранного пункта меню.
Контекстное меню через ресурсы
Если вам нужно создать локализованный продукт, то программное добавление пунктов контекстного меню не подойдёт. В таких случаях используется традиционный способ через файл ресурсов, рекомендованный Google.
Создадим XML-файл res/menu/context_menu.xml для меню, а также добавим в разметку ещё один TextView:
Добавляем код к существующему.
Мы используем похожий код, как и при создании стандартного меню. В результате получим контекстное меню, созданное из ресурсов. При выборе нужного пункта изменится либо цвет, либо размер шрифта в TextView.
Источник
Полный список
В этом уроке мы:
— создадим контекстное меню
Контекстное меню вызывается в Андроид длительным нажатием на каком-либо экранном компоненте. Обычно оно используется в списках, когда на экран выводится список однородных объектов (например письма в почт.ящике) и, чтобы выполнить действие с одним из этих объектов, мы вызываем контекстное меню для него. Но т.к. списки мы еще не проходили, сделаем пример попроще и будем вызывать контекстное меню для TextView.
Project name: P0151_ContextMenu
Build Target: Android 2.3.3
Application name: ContextMenu
Package name: ru.startandroid.develop.contextmenu
Create Activity: MainActivity
Откроем main.xml и нарисуем там два TextView:
Для первого TextView мы сделаем контекстное меню, с помощью которого будем менять цвет текста. Для второго – будем менять размер текста.
Принцип создания контекстного меню похож на создание обычного меню. Но есть и отличия.
Метод создания onCreateContextMenu вызывается каждый раз перед показом меню. На вход ему передается:
— ContextMenu, в который мы будем добавлять пункты
— View — элемент экрана, для которого вызвано контекстное меню
— ContextMenu.ContextMenuInfo – содержит доп.информацию, когда контекстное меню вызвано для элемента списка. Пока мы это не используем, но, когда будем изучать списки, увидим, что штука полезная.
Метод обработки onContextItemSelected аналогичный методу onOptionsItemSelected для обычного меню. На вход передается MenuItem – пункт меню, который был нажат.
Также нам понадобится третий метод registerForContextMenu. На вход ему передается View и это означает, что для этой View необходимо создавать контекстное меню. Если не выполнить этот метод, контекстное меню для View создаваться не будет.
Давайте кодить, открываем MainActivity.java. Опишем и найдем TextView и укажем, что необходимо создавать для них контекстное меню.
Теперь опишем создание контекстных меню. Используем константы для хранения ID пунктов меню.
Обратите внимание, что мы по ID определяем View, для которого вызвано контекстное меню и в зависимости от этого создаем определенное меню. Т.е. если контекстное меню вызвано для tvColor, то мы создаем меню с перечислением цветов, а если для tvSize – с размерами шрифта.
В качестве ID пунктов мы использовали константы. Группировку и сортировку не используем, поэтому используем нули в качестве соответствующих параметров.
Можно все сохранить и запустить. При долгом нажатии на TextView должны появляться контекстные меню.
Но нажатие на них ничего не дает, т.к. мы не прописали обработку в методе onContextItemSelected. Давайте пропишем:
В этом методе мы определяем по ID, какой пункт меню был нажат. И выполняем соответствующие действия: меняем цвет текста для tvColor или размер шрифта для tvSize. Сохраняем, запускаем и проверяем, что контекстные меню теперь реагируют на нажатия и делают то, что от них требуется.
Для расширения кругозора я хотел бы еще кое-что написать по этой теме. Возможно, это покажется пока сложноватым, так что если вдруг будет непонятно, ничего страшного. Итак, мысли вслух.
Мы использовали метод registerForContextMenu (View view) для включения контекстного меню для определенного View. Этот метод принадлежит классу Activity. Я посмотрел исходники этого метода, там написано следующее:
Вспоминаем наш урок по обработчикам и смотрим хелп по методу setOnCreateContextMenuListener (View.OnCreateContextMenuListener l). Получается, что View в качестве обработчика создания контекстного меню использует объект this. В данном случае, этот код в Activity, значит this – это Activity и есть. Т.е. когда View хочет показать контекстное меню, оно обращается к обработчику (Activity), а он уже выполняет свой метод onCreateContextMenu. Т.е. тот же самый принцип, что и при обычном нажатии (Click).
И строка в MainActivity.java:
абсолютно равнозначна этой строке:
Вообще мы можем создать свой объект, реализующий интерфейс View.OnCreateContextMenuListener и использовать его вместо Activity в качестве обработчика создания контекстного меню.
Не забывайте, что для контекстного меню вы также можете использовать XML-способ, который был рассмотрен в конце прошлого урока. Попробуйте сделать этот же урок, но уже с использованием XML-меню.
Полный код урока:
На следующем уроке:
— рисуем экран программно, а не через layout-файл
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Русские Блоги
Долгое нажатие Android Edittext не вызывает контекстное меню
Краткое описание проблемы
когда RecycleView В EditText При повторном использовании прокрутки вверх и вниз я обнаружил, что долгое нажатие EditText Контекстное меню не появляется
анализ
После волны отладки я обнаружил, что при нормальных обстоятельствах при долгом нажатии TextView из performClick() Функция возвращает true , Когда нет всплывающего контекста, эта функция возвращает fasle
Первая находка TextView Длительное пресс-мероприятие performLongClick() , Посмотрите его исходный код
Сначала выполните отладку
- super.performLongClick() Вернуться к false
- mEditor.performLongCLick() Вернуться к true
Отладка, когда меню не появляется
- super.performLongClick() Вернуться к false
- mEdit.performLongClick() Вернуться к false
Тогда проблема в том mEdit.performLongClick() Выше смотрите исходный код
- mInsertionControllerEnabled Да true
Отладка, когда меню не появляется
- mInsertionControllerEnable За false
Тогда проблема находится mInsertionControllerEnabled Логическое значение члена, ищущее место, где атрибут этого члена был изменен, найдено в Editor#prepareCursorControllers Внутри просмотрите исходный код
Здесь вы можете увидеть, где проблема, без отладки ViewGroup.LayoutParams params = mTextView.getRootView().getLayoutParams(); Это предложение, если в ViewHolder Если выполняется при связывании данных, он никогда не может быть WindowManager.LayoutParams Потому что в это время EdtiText Не был attachToWindow
решение
Теперь, когда я знаю, что это EditText Не существует attachToWindow Когда называется Editor#prepareCursorControllers Функция, тогда я attachToWindow Разве потом не достаточно снова вызвать эту функцию?
Поскольку это метод разрешения пакетов, вам нужно найти косвенный вызов и найти setCursorVisible Метод вызывается, пока onAttachToWindow Сначала установите false А затем установите true Вот и все
Источник
Floating toolbar for text selection в Android Marshmallow: разбор нововведения
В Andriod при выделении текста появляется меню с действиями, которые можно выполнить: «Вырезать», «Скопировать», «Отправить». В Android Marshmallow (SDK 23) появилась возможность расширять это меню и давать пользователю легкий доступ к дополнительным возможностям при работе с текстом: «Перевести», «Прокомментировать», «Процитировать».
В процессе подготовке к выступлению на конференции GDG в Нижнем Новгороде я обнаружил, что эта новая возможность крайне плохо документирована, единственная доступная статья не во всем соответствует действительности, и в сети находится исчезающе мало примеров использования этой возможности. Пришлось разбираться самому. Результатами проведенного исследования и хочу поделиться. Это может сэкономить вам достаточно много времени.
Поскольку различные меню в Android появлялись эволюционно, проще всего рассказ начать «от печки». Разработчики с опытом могут смело листать сразу в раздел «Новое» без риска что-нибудь пропустить. Если что – потом вернетесь. Разработчики помоложе могут под спойлерами найти полезные на практике примеры.
Старое
Первое. Меню вульгарис
Меню в Android устроены достаточно однотипно: они описываются с помощью XML, затем в нужный момент в соответствии с этим описанием с помощью MenuInflater создаются соответствующие объекты в памяти, это меню отображается, и информация о нажатии на соответствующий элемент приходит в колбэк.
Обычное меню, которое во времена оно вызывалось нажатием на аппаратную клавишу «Menu», описывается в ресурсах приложения в виде XML-файла.
Пункты меню будут отсортированы по полю android:orderInCategory.
Создается меню вызовом инфлейтера в методе onCreateOptionsMenu().
Информация о выборе пункта меню попадает в метод onOptionsItemSelected().
Все описанное выше приводит к появлению такого меню:
Все просто и привычно.
Второе. Контекстное меню
Контекстное меню – это плавающее меню, которое появляется при длительном нажатии на какой-либо элемент интерфейса. Этот элемент должен быть предварительно зарегистрирован для работы с контекстным меню.
Контекстные меню чаще всего применяются при работе со списками. Но этот рассказ был бы больше про списки, чем про меню, поэтому оставим за рамками статьи. Примеры будут без них.
Рассмотрим простой пример.
Зарегистрировать элемент можно, например, в onCreate():
Дальше все аналогично предыдущему пункту, только внутри других методов (onCreateContextMenu() и onContextItemSelected()):
При долгом нажатии на элемент с текстом появляется контекстное меню.
Третье. Меню в AppBar и Toolbar
Начиная с Android Honeycomb (он же 3.0, он же SDK 11, то есть тоже достаточно давно) аппаратная кнопка Menu была упразднена, а меню стало отображаться в «строке действий», она же «application bar». Появилась возможность часть пунктов меню показать в этой строке в виде иконок, а часть оставить скрытыми до нажатия на находящийся справа значок меню.
Поля для описания иконок и расположения дополнили XML с описанием меню. В остальном это осталось все то же меню с известными нам onCreateOptionsMenu() и onOptionsItemSelected().
Видимая часть меню | Скрытая часть меню, если нажать на «три точки» |
На этом уровне про меню обычно знают все после первой же новичковой книжки. Спасибо, что хватило терпения дочитать досюда, дальше будет интересней.
Четвертое. Режим контекстных действий (Contextual action mode)
Режим контекстных действий, он же «Contextual action mode» позволяет показать пользователю набор действий, которые можно выполнить над выбранным элементом. Как и контекстное меню, этот инструмент удобен при работе со списками, но списки в этой статье мы не рассматриваем.
Для того, чтобы рассмотреть работу этого режима, нам потребуется элемент, который можно «выбрать». Возьмем для примера ToggleButton. Данный режим приложение активирует само, соответственно, сделаем это при изменении статуса ToggleButton:
actionModeCallback – это экземпляр класса ActionMode.Callback, который содержит колбэки для работы с меню. Меню при этом осталось все тем же, все с той же старой доброй механикой:
Обратите внимание на значение, которое мы сохраняем в переменной actionMode. Это экземпляр класса ActionMode, нам он нужен для того, чтобы была возможность изменить заголовок (actionMode.setTitle()), подзаголовок (actionMode.setSubtitle()), а также завершить этот режим (actionMode.finish()). После выполнения действия режим автоматически не завершается, и если нам нужно, то завершить его мы должны сами.
Обрабатывается выбор пользователя тоже привычным способом:
Меню для контекстных действий, очевидно, должно отличаться от основного, поэтому создадим еще один XML c описанием.
Получаем вот такое поведение:
Все старенькое, то есть известное по крайней мере с SDK 11 теперь закончилось, началось неизвестное.
Новое
В Android Marshmallow (он же 6.0, он же SDK 23) в работе меню появилось два новшества. Оба эти новшества еще не поддерживаются Support Library и работают только на устройствах с SDK 23. Поэтому прежде чем вызывать появившиеся методы, необходимо проверять номер SDK устройства, на котором запущено приложение.
Для удобства рассказа мы избавимся от этих проверок, указав minSdkVersion 23.
Пятое. Еще одно контекстное меню
Метод для создания «Режима контекстных действий» (описан выше) был расширен. Вторым параметром startActionMode() можно передать константу, которая задает тип отображения.
Если задать тип ActionMode.TYPE_FLOATING, то меню приобретает следующий вид:
Иконок нет. Расположение – горизонтальное.
Если пунктов много настолько, что не влезают по ширине, то появятся уже знакомые «три точки»:
Все остальное – точно также, как в «Contextual action mode» (см. выше).
Шестое. Расширение меню при выделении текста
Ну и, наконец, то, что было обещано в статье о нововведениях в Android Marshmallow. Появилась возможность дополнить меню, появляющееся при выделении текста, своими пунктами. Анимированная картинка этого чуда была в самом начале статьи, но если хотите, она еще раз под спойлером.
Реализация
Чтобы добиться такого эффекта, сначала нужно создать унаследованный от ActionMode.Callback колбэк. То есть полностью аналогичный тому, что мы создавали двумя разделами выше для «Contextual action mode».
Далее для всех элементов, в которых мы хотим расширить меню при редактировании, нужно указать этот колбэк:
Колбэк, указанный в setCustomSelectionActionModeCallback(), будет использоваться, если есть выделенный текст. Указаный в setCustomInsertionActionModeCallback() – если текста нет. Разделили их потому, что не все действия имеют смысл, когда ничего не выделено, и, соответственно, содержимое появляющихся меню должно быть разным.
На пустом EditText выглядит вот так:
Ой. Куда делось мое меню?
Посмотрите на скриншоты ниже. Есть идея, куда делись все добавленные пункты меню?
Подсказку можно найти здесь:
Поясню. Достаточно велика вероятность то, что во вторую, вертикальную часть меню оставшиеся пункты тоже не поместятся. И там появится скролл. На скриншотах вверху так и случилось.
Проблема в том, никаих признаков скролла пользователю не видно: значок скролла почти сразу исчезает, а край непоместившегося пункта не выглядывает. Завел багу, посмотрим, что создатели этой фичи скажут. code.google.com/p/android/issues/detail?id=195043
Куда опять делось мое меню?
На этот раз другая проблема: меню при fullscreen input mode описанным выше способом не расширяется. Воркэраунд я нашел только один: выключить fullscreen режим с помощью android:imeOptions=«flagNoExtractUi».
Как разместить свой пункт перед стандартными?
Родные пункты меню имеют параметры order от 1 до 5. Поэтому с помощью android:orderInCategory в описании меню задать положение перед родными пунктами нельзя. Но можно изменить порядок пунктов в уже сформированном меню, например, так:
Получаем результат:
Странности в документации
Нормальной документации на расширение меню при выделении текста нет. Есть уже упоминавшаяся статья статья о новинках в Android Marshmallow.
Я несколько десятков раз перечитывал это место, но так и не смог соотнести то, что там написано, с практикой. Рассказываю по порядку.
Источник