如何在特定菜单项之间添加分隔线?
How to add dividers between specific menu items?
背景
我在操作栏(实际上是工具栏)中有一个菜单项,单击它时会显示一个可供选择的项目列表,类似于单选按钮:
<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>
我需要在这个项目列表下面放一个项目,它和列表之间会有一个分隔符。类似于 material 设计指南显示的内容(取自 here):
编辑:这是我想要做的事情的草图:
问题
我找不到办法。
我试过的
我找到的唯一可能的解决方案是:
更改activity(here)的主题,但这也会影响activity
[=的其他菜单项54=]
当菜单项出现在操作栏上时在菜单项之间放置分隔线的方法,但此处它们不会出现在工具栏本身上。它们出现在所选项目的弹出菜单上。
我试过在list和extra item之间放fake item,也试过放group,空group甚至各种属性都试过
遗憾的是没有任何效果。
问题
如何在操作项的弹出菜单的特定项之间添加分隔线?
也许我需要在单击操作项(如 here)时创建自定义弹出菜单?如果是这样,我如何在特定项目之间放置分隔线?
也许使用微调器作为行动项目?
好的,我找到了一个很好的解决方法,但我不确定样式应该是这样的。这就是我所缺少的:
- 项目的背景位于微调器弹出窗口的背景之上,我不确定这样放置是否正确。
- 我将支持库的白色背景用于微调器的弹出窗口。我认为应该有更好的方法让它变白。
- 我需要知道分隔线的正确样式是什么。现在我用了一个简单的
- 缺少操作栏项目样式。我只是用了一个简单的ImageView,我觉得应该不一样。
- 出于某种原因,在某些 Android 版本(可能是 Lollipop 及更低版本)中,项目的背景看起来是黑色而不是白色。
- 微调器有时可能会遇到 setOnItemSelectedListener 问题,但不确定是什么时候。
MainActivity
@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/menu/menu_main.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/layout/spinner_item.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/layout/spinner.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/values/styles.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/drawable/divider.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>
现在:
group1[ item0 item1 item2 ] group1[item3];
更改为:
group1[ item0 item1] group1[item2 item3]
组有一个divider
;
它喜欢那个小组可以在 item
;
之间添加一个 divder
如果divider
不可用,尝试background
;
我从不使用 menu
;
这是我的猜测;
你应该使用动作布局
<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>
然后就可以在代码中添加点击监听了
这可以通过使用弹出 window 和列表视图来完成。在您的列表视图中,您可以有不同的视图类型,例如菜单项和分隔线。
我列出了弹出 window 部分的代码:
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);
然后你可以使用下面的方法来显示弹出窗口window:
PopupWindowCompat.showAsDropDown(mPopupWindow, parent, x, y, gravity);
在列表视图的适配器中,您可以覆盖 getViewTypeCount() 和 getItemViewType() 以支持菜单项布局和分隔线布局,您也可以添加您需要的任何视图类型。
这是我的应用程序中的快照:
我是这样做的:
参考截图:
style.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;
}
});
}
希望对您有所帮助。
对我有用的超级简单的解决方案:
为背景定义一个可绘制对象:
<?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>
从 SDK 版本 28 开始,您可以使用 menu.setGroupDividerEnabled(boolean)
。如果您使用 ContextMenu
这仅在 SDK 28+ 上受支持,但是 MenuCompat
在 onCreateOptionsMenu()
.
中使用时提供向后兼容性
这将在每个不同的 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)
编辑:提问者要求的示例代码:
这是我目前在我的应用程序中使用的代码,位于 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.
}
}
背景
我在操作栏(实际上是工具栏)中有一个菜单项,单击它时会显示一个可供选择的项目列表,类似于单选按钮:
<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>
我需要在这个项目列表下面放一个项目,它和列表之间会有一个分隔符。类似于 material 设计指南显示的内容(取自 here):
编辑:这是我想要做的事情的草图:
问题
我找不到办法。
我试过的
我找到的唯一可能的解决方案是:
更改activity(here)的主题,但这也会影响activity
[=的其他菜单项54=]当菜单项出现在操作栏上时在菜单项之间放置分隔线的方法,但此处它们不会出现在工具栏本身上。它们出现在所选项目的弹出菜单上。
我试过在list和extra item之间放fake item,也试过放group,空group甚至各种属性都试过
遗憾的是没有任何效果。
问题
如何在操作项的弹出菜单的特定项之间添加分隔线?
也许我需要在单击操作项(如 here)时创建自定义弹出菜单?如果是这样,我如何在特定项目之间放置分隔线? 也许使用微调器作为行动项目?
好的,我找到了一个很好的解决方法,但我不确定样式应该是这样的。这就是我所缺少的:
- 项目的背景位于微调器弹出窗口的背景之上,我不确定这样放置是否正确。
- 我将支持库的白色背景用于微调器的弹出窗口。我认为应该有更好的方法让它变白。
- 我需要知道分隔线的正确样式是什么。现在我用了一个简单的
- 缺少操作栏项目样式。我只是用了一个简单的ImageView,我觉得应该不一样。
- 出于某种原因,在某些 Android 版本(可能是 Lollipop 及更低版本)中,项目的背景看起来是黑色而不是白色。
- 微调器有时可能会遇到 setOnItemSelectedListener 问题,但不确定是什么时候。
MainActivity
@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/menu/menu_main.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/layout/spinner_item.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/layout/spinner.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/values/styles.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/drawable/divider.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>
现在:
group1[ item0 item1 item2 ] group1[item3];
更改为:
group1[ item0 item1] group1[item2 item3]
组有一个divider
;
它喜欢那个小组可以在 item
;
divder
如果divider
不可用,尝试background
;
我从不使用 menu
;
这是我的猜测;
你应该使用动作布局
<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>
然后就可以在代码中添加点击监听了
这可以通过使用弹出 window 和列表视图来完成。在您的列表视图中,您可以有不同的视图类型,例如菜单项和分隔线。
我列出了弹出 window 部分的代码:
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);
然后你可以使用下面的方法来显示弹出窗口window:
PopupWindowCompat.showAsDropDown(mPopupWindow, parent, x, y, gravity);
在列表视图的适配器中,您可以覆盖 getViewTypeCount() 和 getItemViewType() 以支持菜单项布局和分隔线布局,您也可以添加您需要的任何视图类型。
这是我的应用程序中的快照:
我是这样做的:
参考截图:
style.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;
}
});
}
希望对您有所帮助。
对我有用的超级简单的解决方案:
为背景定义一个可绘制对象:
<?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>
从 SDK 版本 28 开始,您可以使用 menu.setGroupDividerEnabled(boolean)
。如果您使用 ContextMenu
这仅在 SDK 28+ 上受支持,但是 MenuCompat
在 onCreateOptionsMenu()
.
这将在每个不同的 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)
编辑:提问者要求的示例代码:
这是我目前在我的应用程序中使用的代码,位于 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.
}
}