Как установить прослушиватель длинного щелчка в MenuItem (в NavigationView)?

Как я могу установить прослушиватель длинного клика на MenuItem?

Я попробовал этот ответ, но этот метод для меня не существует. Любые решения?

Код:

Menu menu = navigationView.getMenu();
MenuItem menuItem = menu.findItem(R.id.menu_item);

// TODO set a long click listener on the menuItem.
menuItem.setOnLongClickListener(...); // Method does not exist, any other solutions?

Редактировать: я не хочу устанавливать настраиваемый вид ActionView, я хочу, чтобы прослушиватель длинных кликов охватывал весь MenuItem без настраиваемого представления.


person Thomas Vos    schedule 18.06.2016    source источник
comment
покажи свой код пожалуйста   -  person BooDoo    schedule 18.06.2016
comment
@BooDoo На самом деле нечего показывать, но я добавил немного кода.   -  person Thomas Vos    schedule 18.06.2016
comment
stackoverflow.com/q/23151117/6152781   -  person BooDoo    schedule 18.06.2016
comment
@BooDoo - он хочет сделать событие длинного щелчка по пункту меню, а не по списку   -  person ceph3us    schedule 18.06.2016
comment
@BooDoo Чем это полезно? Я хочу установить прослушиватель длинного клика на MenuItem, а не на ListView...   -  person Thomas Vos    schedule 19.06.2016
comment
Пожалуйста, покажите больше кода хотя бы для всего класса.   -  person Hossein Seifi    schedule 26.06.2016
comment
@HosseinSeifi Это ничему не поможет. Это единственная интересная часть кода.   -  person Thomas Vos    schedule 27.06.2016
comment
@ SuperThomasLab Для меня не очевидно, почему метод setOnLongClickListener(...) недоступен для вас.   -  person Hossein Seifi    schedule 27.06.2016
comment
@HosseinSeifi У вас есть метод? На какую версию API вы ориентируетесь? Я ориентируюсь на API 23/24.   -  person Thomas Vos    schedule 27.06.2016
comment
@HosseinSeifi - см. мою правку   -  person ceph3us    schedule 27.06.2016
comment
@SuperThomasLab Вы когда-нибудь получали четкий ответ на этот вопрос? Я не могу получить решение ниже для работы. Спасибо   -  person drod    schedule 20.05.2017
comment
@drod Нет, к сожалению, у меня не получилось.   -  person Thomas Vos    schedule 20.05.2017


Ответы (6)


один из многих способов (при условии, что мы используем панель инструментов) - этот пример должен дать вам представление о том, как реализовать долгое нажатие на кнопку панели инструментов:

class MyActivity extends Activity {    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        /** get menu inflater */
        MenuInflater menuInflater = getMenuInflater();
        /** Inflate the menu
         * this adds items to the action bar if it is present. */
        menuInflater.inflate(R.menu.menu_home, menu);
        /** find interesting item */
        MenuItem item = menu.findItem(R.id.itemId);
        /** set action view */
        item.setActionView(new ImageButton(this)); // this is a Context.class object
        /** set listener  on action view */
        item.getActionView().setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return false;
            }
        });

        return super.onCreateOptionsMenu(menu);
    }
}

в методе onCreateOptionsMenu — или любом другом методе, когда вы можете получить ссылку на элемент меню (пропустите шаги 1-2):

  1. создать меню / например, надуть
  2. получить пункт меню
  3. создать представление действия, например ImageButton
  4. установить прослушиватель длинного щелчка в представлении действия
  5. установить в пункте меню вид действия

выше я установил представление действия, затем я возвращаю его из пункта меню и устанавливаю прослушиватель (порядок не имеет значения, он может быть и таким образом):

ImageButton imageButton = new ImageButton(Context);
imageButton.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return false;
            }
        });
item.setActionView(imageButton);

пс. вы также можете установить представление изображения в xml в качестве атрибута пункта меню:

 <item
    ... 
    android:actionViewClass="android.widget.ImageButton"
 />

then you can get the action view by cast 

   View menuItemActionView = menu.findItem(R.id.itemId).getActionView();
   if(menuItemActionView != null 
            && ImageButton.class.isAssignableFrom(menuItemActionView.getCLass())) {
        ImageButton imageButton = (ImageButton) menuItemActionView;
   }

Но затем вы устанавливаете прослушиватель длинных кликов только для представления действия, а не для всего элемента. – СуперТомасЛаб

-- нет, вы устанавливаете представление действия для одного элемента, в этом случае вы меняете представление по умолчанию (на виджет ImageButton) для пункта меню - представление действия может быть простым или сложным типом представления

Но что, если вы не хотите менять представление, а хотите оставить представление по умолчанию? – СуперТомасЛаб

пример (это один из многих способов использования наблюдателя дерева макета/установки прослушивателя изменения макета):

    private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            return false;
        }
    };


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        /** get menu inflater */
        MenuInflater menuInflater = getMenuInflater();
        /** Inflate the menu
         * this adds items to the action bar if it is present. */
        menuInflater.inflate(R.menu.menu_home, menu);
        /** geta menu item using findItem(int itemid) */
        MenuItem item = menu.findItem(R.id.itemLogOut);
        /** check if we have item */
        if(item!=null) {
            /** try get its action view */
            View actionView = item.getActionView();
             /** check if action view is already set? */
            if(actionView==null) {
                /** get item id  to comparte later in observer listener*/
                final int itemId = item.getItemId();
                /** if not set on top most window an layout changes listener */
                getWindow().getDecorView()
                           .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                    @Override
                    public void onLayoutChange(View v, int left, int top, int right, 
                      int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                           /** try get view by id we have stored few line up */
                           View viewById = v.getRootView().findViewById(itemId);
                           /** check if we have any result */
                           if(viewById!=null) {
                                /** set our listener */                     
                                viewById.setOnLongClickListener(onLongClickListener);
                                /** remove layout observer listener */
                                v.removeOnLayoutChangeListener(this);
                           }
                    }
                });
            } else {
                /** if set we can add our on long click listener */
                actionView.setOnLongClickListener(onLongClickListener);
            }
        }
  } 

Я пробовал использовать OnLayoutChangeListener, но он по-прежнему не работает. Ничего не изменилось. – СуперТомасЛаб

ДА ЭТО ДЕЛАЕТ - но я знаю причину, по которой это не работает в вашем случае??? - в моем примере мы проверяем, выложен ли элемент просмотра вместо этого изменения, если вид меню выложен, а затем проверяем, содержит ли меню элемент

вот рабочий код для изучения:

https://github.com/c3ph3us/LongClickOnMenuItem

в ответ на другие комментарии:

@ SuperThomasLab Для меня не очевидно, почему метод setOnLongClickListener(...) недоступен для вас. – Хоссейн Сейфи

@HosseinSeifi - посмотрите на интерфейс android.view.MenuItem - он не предоставляет такой метод - так что для хорошего программиста это должно быть очевидно :) почему он не может реализовать метод класса.

person ceph3us    schedule 18.06.2016
comment
Спасибо за ваш ответ. Но где прослушиватель длинных кликов? И как я должен установить это на MenuItem? - person Thomas Vos; 18.06.2016
comment
Но затем вы устанавливаете прослушиватель длинного щелчка только для представления действия, а не для всего элемента. - person Thomas Vos; 21.06.2016
comment
@SuperThomasLab - нет пункта меню (видимый виджет = в данном случае ImageButton)! - person ceph3us; 21.06.2016
comment
Но что, если вы не хотите менять вид, а хотите сохранить вид по умолчанию? - person Thomas Vos; 21.06.2016
comment
Я попробовал OnLayoutChangeListener, но он все еще не работает. Ничего не изменилось. - person Thomas Vos; 22.06.2016
comment
@SuperThomasLab - нет такой вещи, как не может / не может и т. Д. Изучить пример, который я предоставил на github (установите прослушиватель макета ob для просмотра меню, затем посмотрите, выложен ли вид элемента) - person ceph3us; 27.06.2016
comment
Я считаю, что представленные здесь обходные пути - единственный способ заставить это работать. Я не думаю, что вы можете заставить работать долгое нажатие, не предоставляя свой собственный ActionView или решение в виде дерева. В идеале getActionView() для MenuItem по умолчанию и установка прослушивателя с длинным щелчком просто сработают, но Android иногда отстой :-( - person SoftWyer; 11.06.2017
comment
Вам нужно установить разные идентификаторы для каждого элемента. - person EmmanuelMess; 04.01.2018
comment
Отличный ответ. Знаете ли вы, есть ли способ (используя ваш метод, который не изменяет вид элемента меню по умолчанию), чтобы заставить длительное нажатие предотвратить вызов onOptionsItemSelected? - person snapfractalpop; 08.08.2018

Решение

Это совсем не идеально, но все же лучше, чем все предлагают здесь, потому что это работает для всего макета элемента, а не только для части просмотра действий.

Примечание:

  1. Я тестировал его только в библиотеке MaterialComponents 1.1.0-alpha08, поэтому я не не гарантирую, что это будет работать в будущем
  2. Я уже попросил разработчиков предоставить лучший API для этого, но Я не знаю, сделают ли они это или нет
  3. index — это позиция элемента, НО она также содержит позицию: HeaderLayout, Divider, Category (заголовок подменю)

Ну вот код:

val navigationView = findViewById(R.id.navigation_view)
val navigationRecycler = navigationView[0] as RecyclerView // core-ktx extension for ViewGroup
val navigationLayoutManager = navigationRecycler.layoutManager as LinearLayoutManager
val navigationAdapter = navigationRecycler.adapter

if (navigationAdapter != null) {
    navigationRecycler.post { // this line is important
        for (index in 0 until navigationAdapter.itemCount) {
            val item = navigationLayoutManager.findViewByPosition(index)
            item?.setOnLongClickListener {
                Toast.makeText(this, "finally!", Toast.LENGTH_SHORT).show()
                true
            }
        }
    }
}
person massivemadness    schedule 18.07.2019
comment
Но я думаю, что это должно быть «в 0..navigationAdapter.itemCount», иначе последний элемент игнорируется. - person Cyb3rKo; 24.10.2020

Вы можете сделать это следующим образом:

        val homeTab = bottomNavigationView.findViewById<BottomNavigationItemView>(R.id.navigation_home) 
        //R.id.navigation_home id of navigation menu items you provided in menu file for BottomNavigationView

        homeTab.setOnLongClickListener {
              Toast.makeText(this@MainActivity,"Home Long clicked!",Toast.LENGTH_LONG).show()
              true
    }
person Edalat Feizi    schedule 06.08.2019

Вы можете добиться этого:

action_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:support="http://schemas.android.com/apk/res-auto" >

<item
    android:id="@+id/item1"
    support:showAsAction="always">
</item>

custom_action_view.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:paddingRight="5dp" >

<ImageButton
    android:id="@+id/customActionItem"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:background="@drawable/abc_item_background_holo_dark"
    android:src="@drawable/bulb_icon" />

</RelativeLayout>

и код инфлятора меню выглядит следующим образом:

public boolean onCreateOptionsMenu(Menu menu) {
    // TODO Auto-generated method stub
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.action_menu, menu);     

    final MenuItem item1= menu.findItem(R.id.item1);
    MenuItemCompat.setActionView(item1, R.layout.custom_action_view);
    View vItem1= MenuItemCompat.getActionView(item1);

    final ImageButton customActionItem= (ImageButton) vItem1.findViewById(R.id.customActionItem);
    customActionItem.setOnLongClickListener(new OnLongClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            // do something here
        }
    });

    return super.onCreateOptionsMenu(menu);
}
person Sanat Chandravanshi    schedule 27.06.2016
comment
Это то же самое, что и другой ответ. Мне не нужен пользовательский ActionView. Я хочу установить прослушиватель длинного щелчка на обычный элемент без пользовательского представления. - person Thomas Vos; 27.06.2016

Из массивного безумия answer вот небольшая вариация для таргетинга на меню. Я также не думаю, что это стабильно, это похоже на бред, но вложите его в попытку поймать, сохранять спокойствие и двигаться дальше :)

if(navigationAdapter != null) {
            navigationRecycler.post { // this line is important
                for(index in 0 until navigationAdapter.itemCount) {
                    val item = navigationLayoutManager.findViewByPosition(index)
                    item?.setOnLongClickListener {
                        try{
                            Toast.makeText(this, "${nav_view.menu[index - 1 /*Number of children before your menu*/].title}!", Toast.LENGTH_SHORT).show()
                            true
                        } catch (e:Throwable){
                            false
                        }


                    }
                }
            }
        }

person Blessing Charumbira    schedule 26.06.2020

person    schedule
comment
Это может решить вопрос, но вы можете добавить, почему ваше решение работает. Небольшое объяснение имеет большое значение. - person Tavo; 26.11.2019