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

问题描述 投票:2回答:2

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

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

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

java android navigation menuitem
2个回答
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);
}

0
投票

我们选择做这些事并不是因为它们很容易,而是因为它们很难。因为如果我不能这样做,我的用户界面就会被解开。

将下面给出的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添加到您的proguard规则中。

navigation item long press interceptor.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以同样的方式布置actionViews。

使用'androidx.appcompat:appcompat:1.0.2','com.google.android.material:material:1.0.0'进行测试。我有理由相信它是版本安全的。如果getMenuItemParent()needs调整其他AppCompat版本,请告诉我,我将在此处纳入更改。

© www.soinside.com 2019 - 2024. All rights reserved.