在安卓中更改溢出菜单的边距

5
这是Android中上下文菜单的默认位置:

default position

然而,应用程序Inbox将它放得更远离屏幕顶部和右侧边缘:

inbox

有没有相对简单的方法来实现这一点?

我认为你可以阅读https://dev59.com/D4Xca4cB1Zd3GeqPF0Md - BNK
6个回答

5
有没有一种相对简单的方法实现这个目标?
当然有。而且,只需要五行代码。 Konstantin Loginov采用自下而上的方法,你需要在代码/设计中处理所有事情。尽管我欣赏这种方法,但它会增加源代码的复杂性。在采用自定义解决方案之前,最好先检查是否有自上而下的方法可用。
以下是自上而下的版本:
以下代码将放在您活动的基本主题定义中:
<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>

样式OverflowMenuStyle将被定义为:

<style name="OverflowMenuStyle" parent="Widget.AppCompat.PopupMenu.Overflow">
    <item name="android:dropDownHorizontalOffset">-16dp</item>
    <item name="android:dropDownVerticalOffset">16dp</item>
</style>

结果:

结果:

未样式化的:

enter image description here

样式化:

enter image description here

附加说明(对您可能微不足道,但它们可能有助于他人):

典型的应用程序主题设置如下:

/res/values/styles.xml:

<!-- Values defined here apply to all supported API versions unless overridden in children -->
<BaseTheme />

<!-- Defined values apply to all supported API versions unless overridden in res/values-vXX/styles.xml -->
<AppTheme extends BaseTheme />

/res/values-vXX/styles.xml:

<!-- Values defined here apply to all API versions >= XX unless overridden in res/values-vYY/styles.xml where YY > XX -->
<AppTheme extends BaseTheme />

在这种设置中,actionOverflowMenuStyle将在BaseTheme下定义。请注意缺少android:前缀 - 我们正在覆盖由appcompat库提供的actionOverflowMenuStyle,而不是Android系统。

2

关于Inbox应用

你在截图中看到的并不是一个普通的Menu,而是带有阴影背景的FrameLayout。它只是一个自定义视图

enter image description here
你可以使用UI Automator Viewer进行检查。

因此,你也可以使用同样的技巧,而不是充气弹出式菜单PopupMenu,创建一个自定义的View,并将其放置在任何你想要的地方。

如何实现与Menu相同的行为

首先,通过使用Android Action Bar Style Generator(或自己创建一个9patch背景)为弹出菜单生成背景。

然后,获取menu_dropdown_panel.9文件:

enter image description here

并在其中添加间距(我使用Paint.NET:调整画布大小,重新插入旧图像并将黑线移动到画布的两侧):

enter image description here

在样式中将新背景设置为android:popupBackground

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="popupMenuStyle">@style/PopupMenu.Example</item>
</style>

<style name="PopupMenu.Example" parent="@style/Widget.AppCompat.Light.PopupMenu">
    <item name="android:popupBackground">@drawable/menu_dropdown_panel_background</item>
</style>

结果看起来像这样:

输入图像描述输入图像描述
(垂直位置取决于您传递给PopupMenu构造函数的锚点)

使用以下代码显示此PopupMenu

PopupMenu popup = new PopupMenu(MainActivity.this, fab);
popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());
popup.show();

I hope, it helps


这个方法可以正常工作,除非你需要视图重叠在Actionbar上,就像OP发布的图片一样。为了使其重叠,它必须在自己的活动中,该活动没有Actionbar。 - C0D3LIC1OU5
@C0D3LIC1OU5 我倾向于不同意您的观点。它是一个常规工具栏,您可以在其顶部轻松地放置自定义视图,就像我们在收件箱中看到的那样。同样,您可以使用Automator Viewer进行检查。 - Konstantin Loginov
1
@C0D3LIC1OU5 为了避免毫无根据,这里有一个例子,展示如何重叠工具栏:https://dev59.com/zVwY5IYBdhLWcg3wH0tC 收件箱也是同样的做法。(虽然我不会评判它是否理想) - Konstantin Loginov
@C0D3LIC1OU5添加了一个截图,显示了PopupMenuToolbar重叠的情况。运行得非常好 :-) - Konstantin Loginov

1
你可以通过这个解决方案摆脱这些问题,但它不会覆盖菜单,而是会像菜单按钮下面一样运作。如果你想尝试,请继续操作。
创建一个样式。
 <style name="OverflowMenu" parent="Widget.AppCompat.PopupMenu.Overflow" tools:targetApi="21">
    <item name="overlapAnchor">false</item>
    <!--<item name="dropDownVerticalOffset">?attr/actionBarSize</item>-->
    <item name="android:overlapAnchor">false</item>
</style>

然后将其添加到您的基本样式中。
<item name="actionOverflowMenuStyle">@style/OverflowMenu</item>

1

没有直接的方法。但是有一种方法可以模拟这种行为或者创造一种它发生的幻觉。

类似的问题已经在this post中得到了回答。虽然问题略有不同,但答案可能也适用于您的目的。

与其拥有一个实际的溢出菜单,你可以“欺骗”一下。在你的操作栏中放置一个看起来像溢出图标的图标。你应该将showAsAction设置为始终在这个MenuItem上显示。在溢出图标的OnClick事件中,你可以显示一个锚定在MenuItem视图上的ListPopupWindow。如果ListPopupWindow没有出现在您想要的位置,您可以调用ListPopupWindow.setHorizontalOffset()ListPopupWindow.setVerticalOffset()


0

我认为这正是你所需要的,你需要自定义视图。

public void onClick(View v) {
    // code from above
    // ...

    popupMenu.show();

    // Try to force some horizontal offset
    try {
        Field fListPopup = menuHelper.getClass().getDeclaredField("mPopup");
        fListPopup.setAccessible(true);
        Object listPopup = fListPopup.get(menuHelper);
        argTypes = new Class[] { int.class };
        Class listPopupClass = listPopup.getClass();

        // Get the width of the popup window
        int width = (Integer) listPopupClass.getDeclaredMethod("getWidth").invoke(listPopup);

        // Invoke setHorizontalOffset() with the negative width to move left by that distance
        listPopupClass.getDeclaredMethod("setHorizontalOffset", argTypes).invoke(listPopup, -width);

        // Invoke show() to update the window's position
        listPopupClass.getDeclaredMethod("show").invoke(listPopup);
    } catch (Exception e) {
        // Again, an exception here indicates a programming error rather than an exceptional condition
        // at runtime
        Log.w(TAG, "Unable to force offset", e);
    }
}

更多信息请查看this


0

使用默认的溢出菜单实现这个功能并不是很容易。我猜他们添加了一个自定义的溢出按钮来打开一个自定义的Activity(覆盖ActionBar),该Activity具有透明的根视图,以及一个大小和位置合适的CardView用于显示部分。CardView负责边框和高程效果,但可能还有自定义的打开动画。这是定制工作。


这不是CardView,请看我的回答 - 我在那里提供了布局层次结构快照 :-) - Konstantin Loginov
不使用 CardView 意味着您必须手动设置视图样式,这需要耗费时间。即使他们在收件箱应用程序中没有使用 CardView,他们也应该使用它,而不是手动设置视图样式以使其看起来像标准的 CardView。 - C0D3LIC1OU5
这是我无法反驳的事实。顺便说一下,他们在收件箱中有很多各种各样的技巧。我真诚地建议尝试使用Automator和Inbox。例如,我喜欢他们如何解决在横向/平板模式下将一组电子邮件列表放在一个巨大的“卡片”(实际上只是一组卡片)中的问题。 - Konstantin Loginov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接