如何在导航抽屉物品中添加长按功能?

时间:2016-08-18 20:36:50

标签: java android navigation menuitem

正如标题所说,我正在尝试为我应用的导航抽屉中的项目添加长按功能。这些项是动态添加的(不是从navigation_drawer_menu.xml中膨胀),所以我无法通过在xml文件中指定一些属性来解决这个问题。

我查看了Stackoverflow上的几个问题,特别是这个问题:How to set a long click listener on a MenuItem (on a NavigationView)?。我已经实现了setActionView解决方案,但最终我在导航抽屉项目的右边缘获得了一个空白按钮。当我长按文字时,没有任何反应。当我长按小空白按钮时,我得到了我想要的东西。

如何为整个menuItem设置一个OnLongClickListener,而不仅仅是为了它(我假设它是一个按钮)在它的右侧?感谢您阅读,如果需要更多信息,我很乐意帮助您:)

3 个答案:

答案 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;

        }

    });