【问题标题】:How to set a long click listener on a MenuItem (on a NavigationView)?如何在 MenuItem 上(在 NavigationView 上)设置长点击侦听器?
【发布时间】:2016-06-18 16:16:09
【问题描述】:

如何在MenuItem 上设置长按监听器?

我尝试了this answer,但该方法对我来说不存在。有什么解决办法吗?

代码:

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 的长点击监听器,没有自定义 View。

【问题讨论】:

  • 请出示您的代码
  • @BooDoo 没什么可显示的,但我添加了一些代码。
  • @BooDoo - 他想在菜单项而不是列表视图上进行长按事件
  • @BooDoo 这有什么帮助?我想在MenuItem 上设置一个长按监听器,而不是在ListView...

标签: android android-menu android-navigationview


【解决方案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)

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

ps。您还可以将 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

回复其他cmets:

@ SuperThomasLab 我不明白为什么 setOnLongClickListener(...) 方法对您不可用。 ——侯赛因·赛菲

@HosseinSeifi - 看看 android.view.MenuItem 接口 - 它没有提供这样的方法 - 所以对于优秀的程序员来说这应该是显而易见的 :) 为什么他无法实现类方法.

【讨论】:

  • 感谢您的回答。但是长按监听器在哪里呢?我应该如何将其设置为MenuItem
  • 但是您将长按监听器设置为仅操作视图,而不是整个项目。
  • @SuperThomasLab - 不支持菜单项(可见小部件 = 在本例中为 ImageButton)!
  • 但是如果你不想改变视图,但保持默认视图呢?
  • 我相信这里提供的解决方法是让它工作的唯一方法。如果不提供自己的 ActionView 或树视图解决方案,我认为您无法长按工作。理想情况下,默认 MenuItem 上的 getActionView() 并设置一个长按监听器就可以了,但 Android 有时很糟糕:-(
【解决方案2】:

解决方案

这根本不是完美的,但仍然比每个人在这里建议的要好,因为它适用于整个项目布局,而不仅仅是 actionview 的部分

注意:

  1. 我只在MaterialComponents library中测试过 1.1.0-alpha08,所以我不保证以后能用
  2. 我已经为此asked devs to provide better API,但我 不知道能不能成功
  3. index是一个item的位置,BUT它还包含位置: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
            }
        }
    }
}

【讨论】:

  • 但我认为它必须是'in 0..navigationAdapter.itemCount',否则最后一项会被忽略。
【解决方案3】:

你可以这样做:

        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
    }

【讨论】:

    【解决方案4】:

    你可以这样做:

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

    【讨论】:

    • 这与其他答案相同。我不想要自定义 ActionView。我想将长按监听器设置为普通项目,没有自定义视图。
    【解决方案5】:
    mBottomNavigationView.findViewById(menuItemId).setOnLongClickListener(new OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            return true;
        }
    });
    

    【讨论】:

    • 这可能会解决问题,但您可能需要添加您的解决方案为何有效。一点解释就大有帮助。
    【解决方案6】:

    来自 massmadness answer 这里是针对菜单的细微变化。我也不认为这是稳定的,感觉就像一个障碍,但将其嵌套在 try catch 中,保持冷静并继续前进:)

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

    【讨论】:

      【解决方案7】:

      我在下面的导航视图中添加了长按。我想在视图中的支持项目上获得长按事件。

      步骤:

      在我的活动中实现了DrawerLayout.DrawerListener 接口。

      将我的活动设置为 DrawerLayout 的 Drawer Listener。

      DrawerLayout drawer = findViewById(R.id.drawer_layout);
      drawer.addDrawerListener(this);
      

      实现了 onDrawerOpened 方法,我将长按设置为项目。

      @Override
      public void onDrawerOpened(@NonNull View drawerView) {
          View support = findViewById(R.id.nav_support);
          support.setOnLongClickListener(view -> {
              // TODO: Handle the long press here.
              return false;
          });
      }
      

      此解决方案的主要思想是在View 上获取MenuItemsetOnLongClickListenerView。我将它添加到 onDrawerOpened 方法中,因为此时我确信 View 已创建。我之前尝试过获取视图,但它不可用并且findViewById 方法正在返回null

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        • 1970-01-01
        • 2020-04-13
        相关资源
        最近更新 更多