How to set a long click listener on a MenuItem (on a NavigationView)?

前端 未结 6 1556
无人及你
无人及你 2020-12-11 01:49

How can I set a long click listener on a MenuItem?

I tried this answer, but the method doesn\'t exist for me. Any solutions?

Code:

<         


        
相关标签:
6条回答
  • 2020-12-11 02:02

    You can do it this way:

            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
        }
    
    0 讨论(0)
  • 2020-12-11 02:03

    Solution

    This isn't perfect at all, but still better than everyone is suggesting here, because it works on whole item layout, not only on actionview's part.

    Notice:

    1. I tested it only in MaterialComponents library 1.1.0-alpha08, so I don't guarantee that it will work in the future
    2. I already asked devs to provide better API for this, but I don't know if they gonna make it or not
    3. index is the position of an item, BUT it also contains position of: HeaderLayout, Divider, Category (Sub menu header)

    Well, here is the code:

    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
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-11 02:04

    one of many ways (assuming we use Toolbar) - this example should give you the idea how to implement long click on toolbar button :

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

    in method onCreateOptionsMenu - or any other method when you can get menu item reference (omit step 1-2):

    1. create menu / for example by inflate
    2. get menu item
    3. create action view for example ImageButton
    4. set long click listener on action view
    5. set on menu item an action view

    above i set an action view then i get it back from menu item and set listener (the order is no matter it could be also in such way):

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

    ps. you can also set image view in xml as attribute on menu item:

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

    But then you set the long click listener to the action view only, not the whole item. – SuperThomasLab

    -- no you are setting an action view on single element in this case you change a default view (to ImageButton widget) for an menu item - action view could be simple or complex view type

    But what if u don't want to change the view, but keep the default view? – SuperThomasLab

    example (this is one way of many by using a layout tree observer / by setting a layout change listener):

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

    I tried the OnLayoutChangeListener, but it still doesn't work Nothing changed. – SuperThomasLab

    YES IT DOES - but i know the reason why it't is not working in your case ??? - in my example we check if view item is laid out instead of that change if menu view is laid out and then check if menu contain item

    here is working code for you to study:

    https://github.com/c3ph3us/LongClickOnMenuItem

    in reply to other comments:

    @ SuperThomasLab It's not obvious for me why setOnLongClickListener(...) method is not available for you. – Hossein Seifi

    @HosseinSeifi - look at android.view.MenuItem interface - it doesn't provide a such method - so for good programmer this should be obvious :) why he can't reach implementing class method.

    0 讨论(0)
  • 2020-12-11 02:15

    You can achieve by doing this:

    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>
    

    and menu inflater code is as follow:

    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);
    }
    
    0 讨论(0)
  • 2020-12-11 02:24
    mBottomNavigationView.findViewById(menuItemId).setOnLongClickListener(new OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            return true;
        }
    });
    
    0 讨论(0)
  • 2020-12-11 02:26

    From massivemadness answer here is a slight variation to target a menu. I also don't think this is stable, it feels like a bodge but nest it in a try catch, keep calm and move on :)

    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
                            }
    
    
                        }
                    }
                }
            }
    
    
    0 讨论(0)
提交回复
热议问题