正如标题所说,我正在尝试为我应用的导航抽屉中的项目添加长按功能。这些项是动态添加的(不是从navigation_drawer_menu.xml中膨胀),所以我无法通过在xml文件中指定一些属性来解决这个问题。
我查看了Stackoverflow上的几个问题,特别是这个问题:How to set a long click listener on a MenuItem (on a NavigationView)?。我已经实现了setActionView解决方案,但最终我在导航抽屉项目的右边缘获得了一个空白按钮。当我长按文字时,没有任何反应。当我长按小空白按钮时,我得到了我想要的东西。
如何为整个menuItem设置一个OnLongClickListener,而不仅仅是为了它(我假设它是一个按钮)在它的右侧?感谢您阅读,如果需要更多信息,我很乐意帮助您:)
答案 0 :(得分:1)
我遇到了同样的问题,并设法通过挖掘NavigationView的视图层次结构来解决它。
第一步是了解NavigationView的视图层次结构。您可以使用this post中的一段代码打印出NavigationView的视图层次结构。
然后开始挖掘您要定位的视图。就我而言:
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Start digging into the view hierarchy until the correct view is found
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
ViewGroup navigationMenuView = (ViewGroup)navigationView.getChildAt(0);
ViewGroup navigationMenuItemView = (ViewGroup)navigationMenuView.getChildAt(2);
View appCompatCheckedTextView = navigationMenuItemView.getChildAt(0);
// Attach click listener
appCompatCheckedTextView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i("test", "LONG CLICK");
return true;
}
});
return super.onPrepareOptionsMenu(menu);
}
答案 1 :(得分:0)
我们选择做这些事情并不是因为它们很简单,而是因为它们很难。而且因为如果我不能这样做,我的UI将会脱胶。
将下面给出的NavigationItemLongPressInterceptor
类导入您的项目。
NavigationView的菜单项被声明为正常,具有两个附加属性以添加长按行为。
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:showIn="navigation_view">
<group android:id="@+id/home_views">
<item
android:id="@+id/nav_item_1"
android:icon="@drawable/ic_item_1"
android:title="Item 1"
android:checkable="true"
app:actionViewClass=
"com.twoplay.netplayer.controls.NavigationItemLongPressInterceptor"
app:showAsAction="always"
/>
<item
android:id="@+id/nav_item_2"
android:icon="@drawable/ic_item_2"
android:title="Item 2"
android:checkable="true"
app:actionViewClass=
"com.twoplay.netplayer.controls.NavigationItemLongPressInterceptor"
app:showAsAction="always"
/>
</group>
</menu>
为您的活动添加NavigationItemLongPressInterceptor.OnNavigationItemLongClickListener的实现,
并实现onNavigationItemLongClick
方法:
public class MainActivity extends MediaActivity
implements
NavigationView.OnNavigationItemSelectedListener,
NavigationItemLongPressInterceptor.OnNavigationItemLongClickListener
. . .
@Override
public void onNavigationItemLongClick(
NavigationItemLongPressInterceptor.SelectedItem selectedItem,
View view)
{
// supply your NavigationView as an argument.
int menItemId = selectedItem.getItemId(mNavigationView);
switch (id) {
...
case R.id.nav_local_device:
case R.id.nav_upnp_devices: {
showNavigationItemSetAsHomePopupMenu(id,view);
}
break;
}
}
}
您可能必须在保护规则中添加com.twoplay.netplayer.controls.NavigationItemLongPressInterceptor
。
NavigationItemLongPressInterceptor.java:
package com.twoplay.netplayer.controls;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.navigation.NavigationView;
import androidx.annotation.Nullable;
/**
* Attach a long-click handler to a menu item in a NavigationView menu.
*
* To handle long-click of a Navigator menu item, declare the item as normal, and append
* app:actionViewClass="com.twoplay.netplayer.controls.NavigationItemLongPressInterceptor" and
* app:showAsAction="always" attributes:
*
* <menu xmlns:tools="http://schemas.android.com/tools"
* xmlns:app="http://schemas.android.com/apk/res-auto"
* >
*
* <group android:id="@+id/home_views">
* <item
* android:id="@+id/nav_item_1"
* android:icon="@drawable/ic_item_1"
* android:title="Item 1"
* android:checkable="true"
* app:actionViewClass=
* "com.twoplay.netplayer.controls.NavigationItemLongPressInterceptor"
* app:showAsAction="always"
* </item>
* </group>
*
* Your Application class must implement <L NavigationItemLongPressInterceptor.OnNavigationItemLongClickListener/>
* in order to receive notification of long pressed menu items.
*
* You can retrieve the item id of the menu by calling <L SelectedItem.getItemId/> on the
* <L SelectedItem/> provided as an arguement to <L NavigationItemLongPressInterceptor.onNavigationItemLongClick/>
*
* />
*
*/
@SuppressWarnings("unused")
public class NavigationItemLongPressInterceptor extends View {
public NavigationItemLongPressInterceptor(Context context) {
super(context);
init();
}
public NavigationItemLongPressInterceptor(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public NavigationItemLongPressInterceptor(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init()
{
setVisibility(View.INVISIBLE);
setLayoutParams(new ViewGroup.LayoutParams(0,0));
}
public interface OnNavigationItemLongClickListener {
void onNavigationItemLongClick(SelectedItem itemHandle, View view);
}
public static class SelectedItem {
private final View actionView;
private SelectedItem(View actionView) {
this.actionView = actionView;
}
public int getItemId(NavigationView navigationView)
{
return getItemId(navigationView.getMenu());
}
private int getItemId(Menu menu) {
for (int i = 0; i < menu.size(); ++i) {
MenuItem item = menu.getItem(i);
if (item.getActionView() == actionView) {
return item.getItemId();
}
SubMenu subMenu = item.getSubMenu();
if (subMenu != null) {
int itemId = getItemId(subMenu);
if (itemId != -1) {
return itemId;
}
}
}
return -1;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
View parent = getMenuItemParent();
parent.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
OnNavigationItemLongClickListener receiver = getReceiver();
if (receiver == null)
{
throw new RuntimeException("Your main activity must implement NavigationViewLongPressInterceptorView.OnNavigationItemLongClickListener");
}
View parent = getMenuItemParent();
receiver.onNavigationItemLongClick(
new SelectedItem(NavigationItemLongPressInterceptor.this),parent);
return true;
}
});
}
private Activity getActivity() {
Context context = getContext();
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
return (Activity)context;
}
context = ((ContextWrapper)context).getBaseContext();
}
return null;
}
private OnNavigationItemLongClickListener getReceiver() {
Activity activity = getActivity();
if (activity == null) return null;
if (activity instanceof OnNavigationItemLongClickListener)
{
return (OnNavigationItemLongClickListener)activity;
}
return null;
}
private View getMenuItemParent() {
View parent = (View)getParent();
while (true)
{
if (parent.isClickable())
{
return parent;
}
parent = (View) parent.getParent();
}
}
}
此代码以androidx为目标,但可以轻松地反向移植到AppCompat。只需删除androidx导入,然后将其替换为相应的AppCompat导入即可。希望NavigationView
的旧版本以相同的方式布局actionView
。
已使用“ androidx.appcompat:appcompat:1.0.2”,“ com.google.android.material:material:1.0.0”进行了测试。我完全有信心它是版本安全的。让我知道getMenuItemParent()
是否需要对其他AppCompat版本进行调整,我将在此处合并更改。
答案 2 :(得分:0)
我必须做类似的事情,并使用onItemLongClick
https://developer.android.com/reference/android/widget/AdapterView.OnItemLongClickListener.html
我的实现略有不同,尽管我在导航抽屉中有一个可扩展列表,并且每个项目都必须有一个onClick以及onLongClick方法调用,导航抽屉中的每个项目也由以下用户动态添加:该应用程序。
listView.setOnItemLongClickListener(new View.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(HomeActivity.this, id +"", Toast.LENGTH_LONG).show();
return true;
}
});