Как установить прослушиватель длинного клика в 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 без пользовательского представления.

Ответ 1

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

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):

  • создать меню/например, надуть
  • Получить пункт меню
  • создать вид действия, например ImageButton
  • установить длинный клик в режиме просмотра
  • установить в пункте меню вид действия

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

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;
   }

Но тогда вы установите прослушиватель длинного клика только в виде действия, а не на весь элемент. - SuperThomasLab

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

Но что, если вы не хотите менять представление, но сохраняете представление по умолчанию? - SuperThomasLab

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

    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, но он все еще не работает. Ничего не изменилось. - SuperThomasLab

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

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

https://github.com/c3ph3us/LongClickOnMenuItem

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

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

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

Ответ 2

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

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);
}

Ответ 3

Решение

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

Обратите внимание:

  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
            }
        }
    }
}