如何为 FrameLayout 中的多个视图制作浮动上下文菜单?

Posted

技术标签:

【中文标题】如何为 FrameLayout 中的多个视图制作浮动上下文菜单?【英文标题】:How to make a Floating Context Menu for multiple views in a FrameLayout? 【发布时间】:2020-04-02 13:04:46 【问题描述】:

我正在以这种方式将视图添加到FrameLayout

frameLayout.post(new Runnable() 
            @Override
            public void run() 
                for (int i = 0; i < adapter.getCount(); i++) 
                    View view = adapter.getView(i, null, frameLayout);
                    frameLayout.addView(view);
                    registerForContextMenu(view);
                
            
        );

onCreateContextMenu 中,我将选择的视图保存在一个变量中

@Override
    public void onCreateContextMenu(ContextMenu menu, View v,
                                    ContextMenu.ContextMenuInfo menuInfo) 
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getActivity().getMenuInflater();
        inflater.inflate(R.menu.fragment_page_lesson_menu, menu);
        selectedView = v; // Saved view
    

但是在onContextItemSelected 中,当我尝试访问它时,它是null

@Override
    public boolean onContextItemSelected(MenuItem item) 
        switch (item.getItemId()) 
            case R.id.remove:
                db.delete(selectedView.getID()); // Error selectedView is null
                return true;
            default:
                return super.onContextItemSelected(item);
        
    

所有这些代码都在同一个 Fragment 类中。

public class MyFragment 

    private View selectedView;

    // Code...


附加信息。

selectedView 不应为空,因为 onContextItemSelected 是 在 onCreateContextMenu 之后调用,对吗? 如果selectedView 被声明为static,则没有NullPointerException 一切都很好。 frameLayout 只是在 onContextItemSelected 结果为空 (frameLayout.getChildCount()) 时 不是

【问题讨论】:

目前尚不清楚为什么要将Adapter 中的一堆Views 堆叠在FrameLayout 中,但您似乎有多个Fragment 实例主动,有意或无意。为每个活动的Fragment 调用onContextItemSelected() 方法,直到返回true 以指示选择已被处理。如果您一次只应该运行一个 MyFragment 实例,那么您应该找出其他实例的来源。否则,将需要一些繁琐的工作来确保上下文菜单适用于给定的实例和View @MikeM。非常感谢您的评论。我确实使用了FrameLayout ,因为我正在制作日历并且使用ListView 我无法很好地定位视图(view.setY 不起作用)。是的,Fragment 有多个实例,因为我使用的是ViewPager。所以这就是问题所在。将selectedViewstatic 作为解决方案怎么样? 是的,大多数情况下这可能会起作用,但它有点老套,静态的View 引用是一个普遍的禁忌。可能一种更好但不太乏味的方法是首先在onContextItemSelected() 中对selectedView 进行空检查——如果它为空则返回false——然后在onContextMenuClosed() 中设置selectedView = null;。有了这个,你在onCreateContextMenu()中设置selectedView = v;,只有当前的Fragment应该有一个非空的selectedView @MikeM。它有效,谢谢。这就是我一直在寻找的 哎呀,我的建议搞错了。我注意到你覆盖了onOptionsMenuClosed() 而不是onContextMenuClosed(),正如我所建议的那样。我刚刚意识到Fragment 没有onContextMenuClosed() 方法,所以显然你不能这样做,而且你的代码中仍然存在一个微妙的错误。完全摆脱onOptionsMenuClosed() 方法,使用后将selectedView = null; 移动到onContextItemSelected()。你真的应该在casedefault 中都这样做,或者将其重构为最后只有一个return 语句,然后在此之前执行。 【参考方案1】:

来自 Mike M. 的评论

问题在于 MyFragment 存在多个实例,因为它位于 ViewPager 中。 (前面的代码在没有 ViewPager 的情况下工作)

现在的工作代码是:

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
                                    ContextMenu.ContextMenuInfo menuInfo) 
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getActivity().getMenuInflater();
        inflater.inflate(R.menu.fragment_page_lesson_menu, menu);
        selectedView = v;
    


    @Override
    public boolean onContextItemSelected(MenuItem item) 

        if(selectedView == null)
            return false;
        

        if (item.getItemId() == R.id.remove) 
            db.deleteLesson(selectedView.getId());
        
        selectedView = null;
        return true;
    

【讨论】:

以上是关于如何为 FrameLayout 中的多个视图制作浮动上下文菜单?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 UICollectionViewCompositionalLayout 中的不同部分设置多个背景视图

如何为 LOB 应用程序中的多个视图设计 REST API

如何为 uicollectionview 制作“选择环”?

故事板 - 如何为特定视图制作转场

如何为熊猫中的多个变量按列创建所有组合?

如何为按钮制作弹跳效果