首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >RecyclerView项目滑动解除有时会卡住

RecyclerView项目滑动解除有时会卡住
EN

Stack Overflow用户
提问于 2019-03-05 20:30:17
回答 2查看 570关注 0票数 0

我正在使用RecyclerView swipe来显示列表项后面的操作按钮,我的RecyclerView是一个带有底部导航的片段,一切都进行得很顺利,但有时swipe会停止并卡住,所以我不能完全滑动项目。我需要你的帮助。我的代码:

main活动中的代码:

代码语言:javascript
复制
ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeController);
itemTouchhelper.attachToRecyclerView(movelistview);

movelistview.addItemDecoration(new RecyclerView.ItemDecoration() {
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        swipeController.onDraw(c,"action");
    }
});

Swipe Controller类中的代码:

代码语言:javascript
复制
public class SwipeController extends ItemTouchHelper.Callback {

    private static final float buttonWidth = 200;
    private boolean swipeBack = false;
    private ButtonsState buttonShowedState = ButtonsState.GONE;
    private RectF buttonInstance = null;
    private RecyclerView.ViewHolder currentItemViewHolder = null;
    private SwipeControllerActions buttonsActions = null;

    public SwipeController(SwipeControllerActions buttonsActions) {
        this.buttonsActions = buttonsActions;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return makeMovementFlags(0, LEFT);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

    }

    @Override
    public int convertToAbsoluteDirection(int flags, int layoutDirection) {
        if (swipeBack) {
            swipeBack = buttonShowedState != ButtonsState.GONE;
            return 0;
        }
        return super.convertToAbsoluteDirection(flags, layoutDirection);
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ACTION_STATE_SWIPE) {
            if (buttonShowedState != ButtonsState.GONE) {
                // if (buttonShowedState == ButtonsState.LEFT_VISIBLE) dX = Math.max(dX, buttonWidth);
                if (buttonShowedState == ButtonsState.RIGHT_VISIBLE)
                    dX = Math.min(dX, -buttonWidth);
                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            } else {
                setTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }
        }

        if (buttonShowedState == ButtonsState.GONE) {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
        currentItemViewHolder = viewHolder;
    }

    private void setTouchListener(final Canvas c, final RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder, final float dX, final float dY, final int actionState, final boolean isCurrentlyActive) {
        recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                swipeBack = event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP;
                if (swipeBack) {
                    if (dX < -buttonWidth) buttonShowedState = ButtonsState.RIGHT_VISIBLE;
                    //else if (dX > buttonWidth) buttonShowedState  = ButtonsState.LEFT_VISIBLE;

                    if (buttonShowedState != ButtonsState.GONE) {
                        setTouchDownListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
                        setItemsClickable(recyclerView, false);
                    }
                }
                return false;
            }
        });
    }

    private void setTouchDownListener(final Canvas c, final RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder, final float dX, final float dY, final int actionState, final boolean isCurrentlyActive) {
        recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    setTouchUpListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
                }
                return false;
            }
        });
    }

    private void setTouchUpListener(final Canvas c, final RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder, final float dX, final float dY, final int actionState, final boolean isCurrentlyActive) {
        recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    SwipeController.super.onChildDraw(c, recyclerView, viewHolder, 0F, dY, actionState, isCurrentlyActive);
                    recyclerView.setOnTouchListener(new View.OnTouchListener() {
                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            return false;
                        }
                    });
                    setItemsClickable(recyclerView, true);
                    swipeBack = false;

                    if (buttonsActions != null && buttonInstance != null && buttonInstance.contains(event.getX(), event.getY())) {
                    /*if (buttonShowedState == ButtonsState.LEFT_VISIBLE) {
                        buttonsActions.onLeftClicked(viewHolder.getAdapterPosition());
                    }else*/
                        if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) {
                            buttonsActions.onRightClicked(viewHolder.getAdapterPosition());
                        }
                    }
                    buttonShowedState = ButtonsState.GONE;
                    currentItemViewHolder = null;
                }
                return false;
            }
        });
    }

    private void setItemsClickable(RecyclerView recyclerView, boolean isClickable) {
        for (int i = 0; i < recyclerView.getChildCount(); ++i) {
            recyclerView.getChildAt(i).setClickable(isClickable);
        }
    }

    private void drawButtons(Canvas c, RecyclerView.ViewHolder viewHolder, String text) {
        float buttonWidthWithoutPadding = buttonWidth - 0;
        float corners = 0;

        View itemView = viewHolder.itemView;
        Paint p = new Paint();
        int position = viewHolder.getAdapterPosition();
        String button_text = "Report";

        if (position >= 0) {
            if (MainApplication.moves_list.get(position).getMove_userId().equals(MainApplication.user_id)) {
                button_text = "Delete";
            } else {
                button_text = "Report";
            }
        }

        RectF rightButton = new RectF(itemView.getRight() - buttonWidthWithoutPadding, itemView.getTop() + 0, itemView.getRight(), itemView.getBottom() - 0);
        p.setColor(Color.RED);
        c.drawRoundRect(rightButton, corners, corners, p);
        drawText(button_text, c, rightButton, p);

        buttonInstance = null;
        if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) {
            buttonInstance = rightButton;
        }
    }

    private void drawText(String text, Canvas c, RectF button, Paint p) {
        float textSize = 40;
        p.setColor(Color.WHITE);
        p.setAntiAlias(true);
        p.setTextSize(textSize);

        float textWidth = p.measureText(text);
        c.drawText(text, button.centerX() - (textWidth / 2), button.centerY() + (textSize / 2), p);
    }

    public void onDraw(Canvas c, String text) {
        if (currentItemViewHolder != null) {
            drawButtons(c, currentItemViewHolder, text);
        }
    }

}
EN

回答 2

Stack Overflow用户

发布于 2019-06-11 23:31:32

我也遇到过同样的问题。滑动按钮卡在UI中,在recyclerview后面。所以这是我找到的最简单也是最好的解决方案。

在SwipeViewController中新建函数,如下所示

代码语言:javascript
复制
public void setSwipeBack()
{
    swipeBack = false;
    buttonShowedState = ButtonsStates.GONE;

}

并在您的片段中使用此函数,在同一回收器视图中填充数据。如下所示

setSwipeBack();

票数 0
EN

Stack Overflow用户

发布于 2019-09-01 05:23:12

我也有同样的问题,但解决起来很简单。

当父容器拦截你的触摸事件时,就会发生这种情况。任何覆盖ViewGroup.onInterceptTouchEvent(MotionEvent)的ViewGroup都可以做到这一点(例如RecyclerView或ScrollView )。

这将导致当ACTION_CANCEL值稍有变化时从motionEvent返回Y,并将触摸事件发送到父视图。

处理这个问题的正确方法是,一旦您认为需要保留运动事件,就在父视图上调用ViewParent.requestDisallowInterceptTouchEvent(boolean)方法。

这里有一个简单的例子(attemptClaimDrag()方法取自安卓源代码):

代码语言:javascript
复制
/**
 * Tries to claim the user's drag motion, and requests disallowing any
 * ancestors from stealing events in the drag.
 */
private void attemptClaimDrag() {
    // parent = yourView.getParent();
    if (parent != null) {
        parent.requestDisallowInterceptTouchEvent(true);
    }
}

在您的onTouchEvent()或onTouch()中:

代码语言:javascript
复制
@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (iWantToKeepThisEventForMyself(event)) {
            attemptClaimDrag();
        }
        //your logic here
    } else {
        //your logic here
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55002871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档