android 如何在特定菜单项之间添加分隔符?

z9ju0rcb  于 2023-02-20  发布在  Android
关注(0)|答案(8)|浏览(258)

背景

我在操作栏(实际上是工具栏)中有一个菜单项,当单击它时,会显示一个可供选择的项目列表,类似于单选按钮:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:icon="@drawable/..."
        android:title="@string/..."
        app:showAsAction="always">
        <menu>
            <group
                android:id="@+id/..."
                android:checkableBehavior="single">
                <item .../>
                <item .../>
                <item .../>
            </group>
        </menu>
    </item>
</menu>

我需要在这个项目列表下面放一个项目,在它和列表之间有一个分隔线。类似于材料设计指南所显示的内容(摘自此处):

编辑:下面是我想做的事情的草图:

问题是

我找不到办法。

我所尝试的

我找到的唯一可能的解决办法是:
1.更改Activity的主题(here),但这也会影响Activity的其他菜单项
1.方法,当菜单项出现在操作栏上时,在菜单项之间放置分隔符,但这里它们不出现在工具栏本身上。它们出现在选定项的弹出菜单上。
1.我试着在列表和额外项之间放假项,我还试着放一个组,一个空组,甚至尝试了各种属性。
可惜什么都没起作用。

这个问题

如何在操作项弹出菜单的特定项之间添加分隔符?
也许我需要创建一个自定义的弹出菜单,当点击操作项(如here)?如果是这样,我如何放置一个分隔符之间的具体项目?也许使用微调作为一个操作项?

7vhp5slm

7vhp5slm1#

您应该使用操作布局

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".LandingActivity">
    <item
        android:id="@+id/action_cart"
        android:title="cart"
        android:actionLayout="@layout/cart_update_count"
        android:icon="@drawable/shape_notification"
        app:showAsAction="always"/>
</menu>

然后动作布局可具有带分隔符的文本视图。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <View
        android:id="@+id/divider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/divider"/>

    <TextView
        android:id="@android:id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?android:attr/selectableItemBackground"
        android:gravity="center_vertical"          
        android:textAppearance="?attr/textAppearanceListItemSmall"/>

</LinearLayout>

然后可以在代码中添加单击侦听器

vaj7vani

vaj7vani2#

从SDK版本28开始,您可以使用menu.setGroupDividerEnabled(boolean)。如果您使用的是ContextMenu,则仅在SDK 28+上支持,但MenuCompatonCreateOptionsMenu()中使用时提供向后兼容性。
这将在每个不同groupId的操作之间添加一个分隔符,如下所示为0和1:

menu.add(0, getAdapterPosition(), action1, R.string.action1);
menu.add(1, getAdapterPosition(), action2, R.string.action2);
menu.setGroupDividerEnabled(true); 

// Or for MenuCompat < SDK 28:
MenuCompat.setGroupDividerEnabled(menu, true);

文档位于:https://developer.android.com/reference/android/view/Menu#setGroupDividerEnabled(boolean)

    • EDIT:请求者请求的示例代码:**

这是我目前在应用中使用的代码,位于RecyclerView适配器中。它应该也可以用于菜单实现。因为您是通过XML定义菜单,所以只要您引用菜单资源,下面的代码也可以为您工作。结果如下所示:

重写onCreateContextMenu或菜单的相关onCreate..方法,如下所示:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    menu.setHeaderTitle(getStr(R.string.actions_title));

    // Groups 0 and 1, first parameter for menu.add()
    menu.add(0, getAdapterPosition(), 0, R.string.homescreen);
    menu.add(0, getAdapterPosition(), 1, R.string.lockscreen);
    menu.add(0, getAdapterPosition(), 2, R.string.wpLocation_both);
    menu.add(1, getAdapterPosition(), 3, R.string.action_download);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        menu.setGroupDividerEnabled(true);  // This adds the divider between groups 0 and 1, but only supported on Android 9.0 and up.
    }
}
gmol1639

gmol16393#

好吧,我已经找到了一个不错的解决方法,但是我不确定造型应该是这样的。这就是我所缺少的:
1.项目的背景位于微调器弹出窗口的背景之上,我不确定这是否是正确的放置方式。
1.我用支持库的白色背景来弹出spinner,我想应该有更好的方法让它变白。
1.我需要知道什么是正确的风格分隔。现在我用了一个简单的
1.缺少操作栏项样式。我只是使用了一个简单的ImageView,我认为它应该有所不同。
1.出于某种原因,在一些Android版本上(可能是棒棒糖及以下),物品的背景看起来是黑色而不是白色。
1.微调器有时可能会出现setOnItemSelectedListener问题,但不确定何时出现。

主要活动

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    final MenuItem item = menu.findItem(R.id.action_settings);
    final Spinner spinner = ((Spinner) MenuItemCompat.getActionView(item));
    SimpleImageArrayAdapter adapter = new SimpleImageArrayAdapter(this);
    spinner.setAdapter(adapter);
    return true;
}

public class SimpleImageArrayAdapter extends ArrayAdapter<String> {
    private final String[] items = {"item 1", "item 2", "item 3", "extra item"};

    public SimpleImageArrayAdapter(Context context) {
        super(context, 0);
    }

    @Override
    public int getCount() {
        return items.length;
    }

    @Override
    public String getItem(final int position) {
        return items[position];
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        View rootView = convertView == null ? LayoutInflater.from(getContext()).inflate(R.layout.spinner_item, parent, false) : convertView;
        TextView tv = (TextView) rootView.findViewById(android.R.id.text1);
        tv.setTextColor(0xff000000);
        tv.setText(items[position]);
        boolean isLastItem = position == getCount() - 1;
        rootView.findViewById(R.id.action_divider).setVisibility(isLastItem ? View.VISIBLE : View.GONE);
        rootView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        return rootView;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //this is the view that's shown for the spinner when it's closed
        ImageView iv = new ImageView(getContext());
        iv.setImageResource(android.R.drawable.ic_menu_add);
        int viewSize = getDimensionFromAttribute(MainActivity.this, android.support.v7.appcompat.R.attr.actionBarSize);
        iv.setLayoutParams(new ViewGroup.LayoutParams(viewSize, viewSize));
        iv.setScaleType(ScaleType.CENTER_INSIDE);
        iv.setBackgroundResource(getResIdFromAttribute(MainActivity.this, R.attr.selectableItemBackground));
        return iv;
    }

}

public static int getResIdFromAttribute(final Activity activity, final int attr) {
    if (attr == 0)
        return 0;
    final TypedValue typedValue = new TypedValue();
    activity.getTheme().resolveAttribute(attr, typedValue, true);
    return typedValue.resourceId;
}

public static int getDimensionFromAttribute(final Context context, final int attr) {
    final TypedValue typedValue = new TypedValue();
    if (context.getTheme().resolveAttribute(attr, typedValue, true))
        return TypedValue.complexToDimensionPixelSize(typedValue.data, context.getResources().getDisplayMetrics());
    return 0;
}

res/菜单/菜单主文件.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context="com.example.user.myapplication.MainActivity">
    <item
        android:id="@+id/action_settings"
        android:actionLayout="@layout/spinner"
        android:title=""
        app:actionLayout="@layout/spinner"
        app:showAsAction="always"
        />
</menu>

res/布局/微调项.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/action_divider"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/divider"/>

    <TextView
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?android:attr/selectableItemBackground"
        android:gravity="center_vertical"
        android:minHeight="?attr/listPreferredItemHeightSmall"
        android:paddingEnd="?attr/listPreferredItemPaddingRight"
        android:paddingLeft="?attr/listPreferredItemPaddingLeft"
        android:paddingRight="?attr/listPreferredItemPaddingRight"
        android:paddingStart="?attr/listPreferredItemPaddingLeft"
        android:textAppearance="?attr/textAppearanceListItemSmall"/>

</LinearLayout>

res/布局/微调器.xml

<?xml version="1.0" encoding="utf-8"?>
<Spinner
    android:id="@+id/spinner"
    style="@style/SpinnerWithoutArrow"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

res/值/样式.xml

<style name="SpinnerWithoutArrow" parent="@style/Widget.AppCompat.Spinner">
    <item name="android:background">@null</item>
    <item name="android:popupBackground">@drawable/abc_popup_background_mtrl_mult</item>
</style>

res/可绘制/分隔符.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size
        android:height="1dp"/>
    <solid android:color="#FFff0000" />
</shape>
huwehgph

huwehgph4#

这可以通过使用弹出窗口和列表视图来完成。在列表视图中,您可以有不同的视图类型,如菜单项和分隔符。
我列出了弹出窗口部分的代码:

LayoutInflater inflater = LayoutInflater.from(context);
    View view = inflater.inflate(R.layout.option_menu, null);
    ListView listView = (ListView) view.findViewById(R.id.listView);
    listView.setDivider(null);

    mAdapter = new OptionListAdapter(context, options);
    listView.setAdapter(mAdapter);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            //TODO: The code when item is clicked.
        }
    });

    mPopupWindow = new PopupWindow(context, null, R.attr.popupMenuStyle);
    mPopupWindow.setFocusable(true); // otherwise on android 4.1.x the onItemClickListener won't work.
    mPopupWindow.setContentView(view);
    mPopupWindow.setOutsideTouchable(true);

    int height = 0;
    int width = 0;
    float density = context.getResources().getDisplayMetrics().density;
    int minWidth = Math.round(196 * density); // min width 196dip, from abc_popup_menu_item_layout.xml
    int cellHeight = context.getResources().getDimensionPixelOffset(R.dimen.option_height);
    int dividerHeight = context.getResources().getDimensionPixelOffset(R.dimen.divider_height);
    final int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    for (int i = 0; i < mAdapter.getCount(); i++) {
        Object item = mAdapter.getItem(i);
        if (item != null) {
            View childView = mAdapter.getView(i, null, listView);
            childView.measure(widthMeasureSpec, heightMeasureSpec);
            height += cellHeight;
            width = Math.max(width, childView.getMeasuredWidth());
        } else {
            height += dividerHeight; // divider
        }
    }
    width = Math.max(minWidth, width);
    Drawable background = mPopupWindow.getBackground(); // 9-pitch images
    if (background != null) {
        Rect padding = new Rect();
        background.getPadding(padding);
        height += padding.top + padding.bottom;
        width += padding.left + padding.right;
    }
    mPopupWindow.setWidth(width);
    mPopupWindow.setHeight(height);
    mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);

然后,您可以使用以下方法显示弹出窗口:

PopupWindowCompat.showAsDropDown(mPopupWindow, parent, x, y, gravity);

在列表视图适配器中,您可以覆盖getViewTypeCount()和getItemViewType()以支持菜单项布局和分隔符布局,还可以添加所需的任何视图类型。
下面是我的应用程序中的快照:

qyzbxkaa

qyzbxkaa5#

在MDC-Android的Material 3 Design中,制作每组菜单项,调用setGroupDividerEnabled(Boolean)
分隔符将插入到组或菜单项之间。

MyActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    ...
    binding.toolbar.menu.setGroupDividerEnabled(true)
}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/item0"
        android:title="item0"
        app:showAsAction="never" />

    <item
        android:id="@+id/item1"
        android:title="item1"
        app:showAsAction="never" />

    <group android:id="@+id/group0">
        <item
            android:id="@+id/item2"
            android:title="group0 item2"
            app:showAsAction="never" />
    </group>

    <group android:id="@+id/group1">
        <item
            android:id="@+id/item3"
            android:title="group1 item3"
            app:showAsAction="never" />

        <item
            android:id="@+id/item4"
            android:title="group1 item4"
            app:showAsAction="never" />
    </group>

</menu>
uubf1zoe

uubf1zoe6#

我是这么做的:

参考屏幕截图:

样式.xml文件:

<style name="popup" parent="Widget.AppCompat.ListView.DropDown">
            <item name="android:divider">@color/colorPrimary</item>
            <item name="android:dividerHeight">1dp</item>
            <item name="android:textColor">@color/colorPrimary</item>
            <item name="android:itemBackground">@android:color/white</item>
    </style>

 <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

        <!--- Customize popmenu -->
        <item name="android:dropDownListViewStyle">@style/popup</item>

    </style>

Java代码:

private void showPopup(View v) {
        Context wrapper = new ContextThemeWrapper(this, R.style.popup);
        PopupMenu mypopupmenu = new PopupMenu(wrapper, v);
        MenuInflater inflater = mypopupmenu.getMenuInflater();
        inflater.inflate(R.menu.menu_patient_language, mypopupmenu.getMenu());
        mypopupmenu.show();
        mypopupmenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                txtPreferredLanguage.setText(item.getTitle().toString());
                switch (item.getItemId()) {
                    case R.id.menuEnglish:
                        // Your code goes here
                        break;

                    case R.id.menuFrench:
                        // Your code goes here
                        break;
                }
                return false;
            }
        });
    }

希望这对你有帮助。

uyhoqukh

uyhoqukh7#

超级简单的解决方案,为我工作:

定义背景的可绘制对象:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@android:color/white"/>
    <stroke
        android:width="3dp"
        android:color="@color/colorPrimary"/>

</shape>

然后在样式中使用背景:

<style name="bluetooth_popup" parent="@android:style/Widget.DeviceDefault.Light.PopupMenu">
    <item name="android:textColor">@color/colorPrimary</item>
    <item name="android:textStyle">bold</item>
    <item name="android:textAllCaps">true</item>
    <item name="android:background">@android:color/transparent</item>
    <item name="android:itemBackground">@drawable/bluetooth_popup_buttons</item>
z4iuyo4d

z4iuyo4d8#

现在:

group1[ item0 item1 item2 ] group1[item3];

变更为:

group1[ item0 item1] group1[item2 item3]

基团具有divider;它喜欢在item之间加一个divder;
如果divider不可用,请尝试background;我从不使用menu;这是我猜测;

相关问题