中断Android中的最后一次触摸事件

Posted

技术标签:

【中文标题】中断Android中的最后一次触摸事件【英文标题】:Interrupting last touch event in Android 【发布时间】:2020-09-17 08:18:51 【问题描述】:

当用户长按列表项时,我的应用程序将 ListPopupWindow 显示为上下文菜单。显示上下文菜单后,背景仍然可以拖动,直到用户抬起手指为止。您可以在附加的 gif 中看到行为。 我想知道如何中断这种拖动。

TrackListAdapter.java:

private final float[] longClickLastTouchDownXY = new float[2];

@Override
@CallSuper
public void onBindViewHolder(VH holder, int position) 
    holder.itemView.setOnTouchListener((v, event) -> 
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) 
            longClickLastTouchDownXY[0] = event.getX();
            longClickLastTouchDownXY[1] = event.getY();
        
        return false;
    );
    holder.itemView.setOnLongClickListener(v -> 
        if (onItemLongClickListener != null) 
            onItemLongClickListener.onItemLongClick((ViewGroup) v,
                    (int) longClickLastTouchDownXY[0], (int) longClickLastTouchDownXY[1],
                    holder.getAdapterPosition());
            return true;
        
        return false;
    );

TrackListFragment.java:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) 
    View layout = inflater.inflate(R.layout.list_track, container, false);
    ButterKnife.bind(this, layout);


    tracksList.setAdapter(tracksAdapter);
    tracksAdapter.setOnItemLongClickListener(this::showTrackContextMenu);

    return layout;


private void showTrackContextMenu(ViewGroup rootView, float x, float y, int itemPosition) 
    Track selectedTrack = tracksAdapter.get(itemPosition);
    ListPopupWindow popupWindow = new ListPopupWindow(requireContext());
    ListPopupWindowAdapter adapter = new ListPopupWindowAdapter(requireContext(), R.menu.track_menu);
    popupWindow.setAdapter(adapter);

    View tempView = new View(requireContext());
    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(0, 0);
    tempView.setLayoutParams(lp);
    tempView.setX(x - rootView.getPaddingLeft());
    tempView.setY(y - rootView.getPaddingTop());
    rootView.addView(tempView);

    popupWindow.setAnchorView(tempView);
    popupWindow.setModal(true);
    popupWindow.setOnDismissListener(() -> rootView.removeView(tempView));
    popupWindow.show();

【问题讨论】:

你为recyclerview设置了什么LayoutManager? @HasanBouTaam LinearLayoutManager 通过 xml 【参考方案1】:

理论上应该可行,我没有测试过:

用于冻结 RecyclerView 的垂直滚动:

RecyclerView 有一个名为setLayoutFrozen(boolean frozen); 的方法,该方法似乎会在RecyclerView 处于活动状态时阻止其TouchEvent(当您将frozen 设置为true 时)。

现在我假设您的方法showTrackContextMenu(.....) 在您长按列表中的项目时被调用(看来您为此创建了一个界面)。无论如何尝试在此方法结束时冻结 RecyclerView。像这样:

private void showTrackContextMenu(ViewGroup rootView, float x, float y, int itemPosition) 

.......
.......
.......

popupWindow.show();

//here
yourRecyclerView.setLayoutFrozen(true);


如果您想解除冻结以便再次滚动,只需调用以下代码:

yourRecyclerView.setLayoutFrozen(false);

对于冻结 ViewPager:

好的,我找不到用于冻结 ViewPager 的方法,你唯一能做的就是制作一个自定义 ViewPager 并使用它,让它做你想做的事:

class MyViewPager extends ViewPager

private boolean frozen = false;

public MyViewPager(Context context)
super(context);


public MyViewPager(Context context, AttributeSet attrs) 
super(context, attrs);


public void freezeViewPager(boolean frozen)
this.frozen = frozen;


@Override
 public boolean onTouchEvent(MotionEvent event) 
if(frozen)
 return false;
else
 return super.onTouchEvent(event);





然后你在 xml 中使用上面的 ViewPager,而不是你正在使用的默认的。

冻结它:

.......

popupWindow.show();

//here freeze recyclerView
yourRecyclerView.setLayoutFrozen(true);
//here freeze view pager
myViewPager.freezeViewPager(true);

停止冻结:

myViewPager.freezeViewPager(false);

【讨论】:

是的,您的答案对于垂直拖动是正确的。我的错误是我忘记指出使用水平滚动的 ViewPager 也是必要的。 ViewPager 包含在父片段中 当然我可以创建 LockableViewPager 并添加方法来冻结它,就像在 recyclerview 中一样,但我在其他地方也需要这种行为,ViewPager 没有使用。这就是为什么我询问中断触摸的原因 你在其他地方需要什么行为? 在不拖动的情况下显示上下文菜单。对不起我的英语不好) 检查我的更新,您必须像我展示的那样构建自己的自定义查看器。

以上是关于中断Android中的最后一次触摸事件的主要内容,如果未能解决你的问题,请参考以下文章

Android触摸事件-TouchEventHelper

为啥触摸事件会破坏我的 Android 帧率?

单击事件与触摸事件的区别

Android触摸事件分发机制

Android中的触摸或单击事件ViewPagerIndicator

在 Android 中的多个视图上同时处理触摸事件