В этом уроке я покажу вам, как реализовать простое контекстное меню во фрагменте при использовании View Binding для любого элемента (Button, TextView, Layout,…). Я также покажу Вам, как включить/отключить или даже скрыть определенный пункт в контекстном меню.
Давайте создадим новый проект — откройте«Android Studio», выберите «Новый»,и затем « Новый проект».
Теперь выберите «Пустая активность» и нажмите «Далее».
Если вы учатся, но мой совет - изменить их, чтобы привыкнуть к этому.
Выберите «Kotlin» в качестве вашего языка, и я буду работать здесь с минимальным SDK API 29, но вы можете использовать любой, который вам нравится.
Нам нужно создать новый каталог ресурсов, который называется «menu» (если он у вас уже есть, пропустите этот шаг).
Найдите папку «res» и щелкните ее правой кнопкой мыши. Выберите «Создать», а затем «Каталог ресурсов Android».
Выберите «меню» в разделе «Тип ресурса» и нажмите «ОК», ничего не меняя.
Следующий шаг — щелкнуть правой кнопкой мыши вновь созданную папку меню, выбрать «Создать», а затем «Файл ресурсов меню». Назовите его как хотите и нажмите «ОК».
Наконец, давайте создадим или меню! Наш main_menu.xml будет выглядеть так:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/copyItem" android:title="Copy" /> <!--android:icon="@drawable/ic_new_game"--> <item android:id="@+id/shareItem" android:title="Share" /> </menu>
Таким образом, мы будем использовать наш идентификатор, чтобы найти конкретный элемент и использовать его позже в коде, заголовок будет отображаться в нашем меню, и вы можете добавить конкретный значок рядом с вашим заголовком.
Теперь давайте создадим пустой фрагмент, щелкнув правой кнопкой мыши имя нашего пакета, «Новый», «Фрагмент», а затем «Фрагмент (пустой)». .
Назовите его, как хотите, и нажмите «Готово».
Теперь у нас будет «fragment_example.xml» в папке «layout» и «ExampleFragment.kt» в папке нашего пакета.
Теперь давайте отредактируем activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/constraintLayoutActivity" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragmentContainerView" android:name="com.jskako.contextmenuexample.ExampleFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Итак, теперь у нас будет контейнер фрагментов, в котором будет храниться только что созданный фрагмент примера.
Теперь давайте отредактируем fragment_example.xml.
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ExampleFragment"> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/constraintLayoutFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/buttonFragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="Test Fragment" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <com.google.android.material.textfield.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@+id/buttonFragment"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/exampleET" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:hint="Edit Text fragment" /> </com.google.android.material.textfield.TextInputLayout> </androidx.constraintlayout.widget.ConstraintLayout> </FrameLayout>
Теперь, когда у нас есть макеты и main_menu, пришло время серьезно поработать. Давайте начнем с реализации привязки в нашем ExampleFragment.kt.
Сначала откройте build.gradle и добавьте этот код в android{}ниже buildFeatures, после добавления кода нажмите «Синхронизировать сейчас”.
buildFeatures { viewBinding true }
Так это будет выглядеть так:
Теперь давайте откроем наш ExampleFragment.kt и отредактируем его:
package com.jskako.contextmenuexample import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.jskako.contextmenuexample.databinding.FragmentExampleBinding class ExampleFragment : Fragment() { private var binding: FragmentExampleBinding? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentExampleBinding.inflate(inflater, container, false) return binding?.root } }
Наконец, долгожданный момент — давайте создадим контекстное меню.
В нашей функции OnCreateView мы зарегистрируем элементы, для которых мы хотим создать контекстное меню, нажав и удерживая их. Я добавлю каждый элемент только для примера, но вы можете использовать любой элемент, который хотите.
binding?.apply { registerForContextMenu(this.buttonFragment) } binding?.apply { registerForContextMenu(this.exampleET) } //binding?.apply { registerForContextMenu(this.constraintLayoutFragment) }
Таким образом, наш OnCreateView в ExampleFragment будет выглядеть так:
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentExampleBinding.inflate(inflater, container, false) binding?.apply { registerForContextMenu(this.buttonFragment) } binding?.apply { registerForContextMenu(this.exampleET) } return binding?.root }
Теперь нам нужно переопределить функцию onCreateContextMenu и раздуть или создать main_menu, который мы создали ранее.
override fun onCreateContextMenu( menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo? ) { super.onCreateContextMenu(menu, v, menuInfo) menu.setHeaderTitle("Pick option") requireActivity().menuInflater.inflate(R.menu.main_menu, menu) }
И последний шаг — переопределить onContextItemSelected, где мы указываем, что делать, когда элемент выбран из нашего контекстного меню.
override fun onContextItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.copyItem -> { someCopyFun() } R.id.shareItem -> { someShareFun() } } return super.onContextItemSelected(item) }
Таким образом, наш ExampleFragment выглядит следующим образом:
package com.jskako.contextmenuexample import android.os.Bundle import android.view.* import androidx.fragment.app.Fragment import com.jskako.contextmenuexample.databinding.FragmentExampleBinding class ExampleFragment : Fragment() { private var binding: FragmentExampleBinding? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentExampleBinding.inflate(inflater, container, false) binding?.apply { registerForContextMenu(this.buttonFragment) } binding?.apply { registerForContextMenu(this.exampleET) } return binding?.root } override fun onCreateContextMenu( menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo? ) { super.onCreateContextMenu(menu, v, menuInfo) menu.setHeaderTitle("Pick option") requireActivity().menuInflater.inflate(R.menu.main_menu, menu) } override fun onContextItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.copyItem -> { someCopyFun() } R.id.shareItem -> { someShareFun() } } return super.onContextItemSelected(item) } private fun someShareFun() {} private fun someCopyFun() {} }
Давайте проверим, работает ли это, создав наше приложение:
И последнее, но не менее важное: давайте посмотрим, как мы можем отключить или скрыть какой-либо элемент из контекстного меню.
Допустим, если наше поле Редактировать текст ("exampleET") пусто, мы хотим отключить элемент Копировать и скрыть Поделиться item — нам нужно добавить несколько строк в наше onCreateContextMenu:
//Disable copy menu.findItem(R.id.copyItem).isEnabled = !binding?.exampleET?.text.isNullOrEmpty() //Hide share menu.findItem(R.id.shareItem).isVisible = !binding?.exampleET?.text.isNullOrEmpty()
Итак, наше onCreateContextMenu будет выглядеть так:
override fun onCreateContextMenu( menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo? ) { super.onCreateContextMenu(menu, v, menuInfo) menu.setHeaderTitle("Pick option") requireActivity().menuInflater.inflate(R.menu.main_menu, menu) //Disable copy menu.findItem(R.id.copyItem).isEnabled = !binding?.exampleET?.text.isNullOrEmpty() //Hide share menu.findItem(R.id.shareItem).isVisible = !binding?.exampleET?.text.isNullOrEmpty() }
В итоге получаем что-то вроде:
Теперь Вы должны получить представление о том, как работать с контекстным меню. Вы можете зарегистрировать контекстное меню на любой понравившийся элемент — даже на макеты.
binding?.apply { registerForContextMenu(this.constraintLayoutFragment) }
Надеюсь, вам понравился туториал и приятного кодинга :)
Найдите этот проект на GitHub: https://github.com/jskako/Android-Kotlin-examples/tree/main/ContextMenu-example-main