RecycleView如何设置点击拖动和定时拖动

本文分析了RecyclerView中通过点击而非默认的长按方式触发拖拽功能的实现方法,并深入探讨了startDrag()方法及其相关逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天说说RecycleView的拖拽时间的控制。博主在百度和谷歌上面都进行了无数次的搜索,却没有发现有任何一个是针对RecycleView的拖拽按下什么时候触发拖拽事件的文章。哎,可以说是难为死博主了,最后在大牛的帮助下在源码中找到了出路。废话不多说,接下来贴出源码分析这个难死博主的简单问题。

首先贴出一个大神对RecycleView的拖拽和滑动删除的博客地址,博主也是在这个基础上进行接下来的讲解的。
Android一步一步带你实现RecyclerView的拖拽和侧滑删除功能
这篇文章博主个人认为写更加容易理解一点,所以推荐这篇博客,如果大家是初识RecycleView的话,建议先看这篇文章再看博主的。接下来博主就在大神的基础上接着讲时间的问题

startDrag();

博主一开始的思路是竟然它是长按后会触发拖拽的方法的,博主在callback回中打Log,发现当我们触发长按之后第一个调用的是getMovementFlags()。于是想到我们应该用点击来代替长按,触发此方法。

重点方法一:
贴出第一段代码:

    /**
     * Starts dragging the provided ViewHolder. By default, ItemTouchHelper starts a drag when a
     * View is long pressed. You can disable that behavior by overriding
     * {@link ItemTouchHelper.Callback#isLongPressDragEnabled()}.
     * <p>
     * For this method to work:
     * <ul>
     * <li>The provided ViewHolder must be a child of the RecyclerView to which this
     * ItemTouchHelper
     * is attached.</li>
     * <li>{@link ItemTouchHelper.Callback} must have dragging enabled.</li>
     * <li>There must be a previous touch event that was reported to the ItemTouchHelper
     * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener
     * grabs previous events, this should work as expected.</li>
     * </ul>
     *
     * For example, if you would like to let your user to be able to drag an Item by touching one
     * of its descendants, you may implement it as follows:
     * <pre>
     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
     *         public boolean onTouch(View v, MotionEvent event) {
     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
     *                 mItemTouchHelper.startDrag(viewHolder);
     *             }
     *             return false;
     *         }
     *     });

     * @param viewHolder The ViewHolder to start dragging. It must be a direct child of
     *                   RecyclerView.
     * @see ItemTouchHelper.Callback#isItemViewSwipeEnabled()
     */
    public void startDrag(ViewHolder viewHolder) {
        if (!mCallback.hasDragFlag(mRecyclerView, viewHolder)) {
            Log.e(TAG, "Start drag has been called but swiping is not enabled");
            return;
        }
        if (viewHolder.itemView.getParent() != mRecyclerView) {
            Log.e(TAG, "Start drag has been called with a view holder which is not a child of "
                    + "the RecyclerView which is controlled by this ItemTouchHelper.");
            return;
        }
        obtainVelocityTracker();
        mDx = mDy = 0f;
        select(viewHolder, ACTION_STATE_DRAG);
    }

一眼看去很多东西但是,代码就那么简单几行,所以耐心点。博主再拆分讲解。。。。

这里面的意思大致就是说系统默认的是长按的时候触发拖拽,你可以disable它,然后重写这个方法(当然我们需要实现的功能不必去重写方法,后面会介绍用法。)

这里面的意思大致就是说系统默认的是长按的时候触发拖拽,你可以disable它,然后重写这个方法(当然我们需要实现的功能不必去重写方法,后面会介绍用法。

这段就是一个简单的例子,告诉我们应该怎么去使用这个方法,实现我们需要的功能,点击就触发拖动。

这段就是一个简单的例子,告诉我们应该怎么去使用这个方法,实现我们需要的功能,点击就触发拖动。
这才是我们的方法,是不是很简单,就两个if语句而已。注意到的是参数是一个ViewHolder, 不要想的太多。简单点,说话的方式简单点,就是直接调用这个方法就可以实现点击就实现拖拽。

这才是我们的方法,是不是很简单,就两个if语句而已。注意到的是参数是一个ViewHolder, 不要想的太多。简单点,说话的方式简单点,就是直接调用这个方法就可以实现点击就实现拖拽。

到此我们就已经可以实现点击拖拽了。如果想自己控制时间,我想大家都想的到,用handler或者线程的形式,这就不多说了。

显然大家都想进一步了解是怎么去实现的,首先看第一个if语句:

点击hasDragFlag()进入方法:

    private boolean hasDragFlag(RecyclerView recyclerView, ViewHolder viewHolder) {
            final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder);
            return (flags & ACTION_MODE_DRAG_MASK) != 0;
        }

很简单的几行代码,继续点击进入getAbsoluteMovementFlags():

      final int getAbsoluteMovementFlags(RecyclerView recyclerView,
                ViewHolder viewHolder) {
            final int flags = getMovementFlags(recyclerView, viewHolder);
            return convertToAbsoluteDirection(flags, ViewCompat.getLayoutDirection(recyclerView));
        }

到这里也是简单的几行代码,但是博主注意到有一个方法很眼熟。没错getMovementFlags(), 这个方法。当我们根据系统的默认实现长按拖拽实现的时候,我们触发长按之后,第一个触发的就是这个方法,这个方法也是设置拖拽和滑动方向的方法。和博主一开始的思路是对的,系统提供的方法也是触发它。

今天就到这里吧,不知道分析的对与否,当然博主只分析了一小部分,还有其他的没有分析,比如第二个if语句和接下来的三个方法,也都是重点,等博主以后能力提升后会再次改进这篇文章和补全其他几个方法的深入解析。还希望大神可以多多指点。

如果您想要在RecyclerView中监听拖动事件并判断它是否在item内,可以使用以下步骤: 1. 在您的RecyclerView.Adapter中,为每个item设置一个OnTouchListener,并将其添加到itemView中。 2. 在OnTouchListener中,您可以监听ACTION_DOWN、ACTION_MOVEACTION_UP事件,并在ACTION_DOWN事件中使用View.startDrag()方法来启动拖动操作。 3. 在您的RecyclerView中,使用setOnDragListener()方法设置一个DragEventListener,以便在拖动操作发生时收到通知。 4. 在DragEventListener的onDrag()方法中,检查拖动事件是否在item内。您可以使用以下方法来判断: a. 获取拖动事件的xy坐标 b. 获取RecyclerView中所有可见的item的位置大小 c. 对于每个item,检查拖动事件是否在item内,如果是,则返回true,否则返回false。 d. 如果所有的item都不包含拖动事件,则返回false。 以下是一个示例代码,说明如何在RecyclerView中监听拖动事件并判断它是否在item内: ``` public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> mData; public MyAdapter(List<String> data) { mData = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_layout, parent, false); itemView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { v.startDrag(null, new View.DragShadowBuilder(v), null, 0); return true; } return false; } }); return new ViewHolder(itemView); } @Override public void onBindViewHolder(ViewHolder holder, int position) { String item = mData.get(position); holder.mTextView.setText(item); } @Override public int getItemCount() { return mData.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(View itemView) { super(itemView); mTextView = itemView.findViewById(R.id.text_view); } } } public class MyActivity extends AppCompatActivity { private RecyclerView mRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = findViewById(R.id.recycler_view); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(new MyAdapter(Arrays.asList("Item 1", "Item 2", "Item 3"))); mRecyclerView.setOnDragListener(new View.OnDragListener() { @Override public boolean onDrag(View v, DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: return true; case DragEvent.ACTION_DRAG_LOCATION: return isInsideItem(event.getX(), event.getY()); case DragEvent.ACTION_DROP: // Handle drop event return true; default: return false; } } }); } private boolean isInsideItem(float x, float y) { Rect rect = new Rect(); for (int i = 0; i < mRecyclerView.getChildCount(); i++) { View child = mRecyclerView.getChildAt(i); child.getGlobalVisibleRect(rect); if (rect.contains((int) x, (int) y)) { return true; } } return false; } } ``` 在此示例中,我们为每个item设置了一个OnTouchListener,并在其中启动了拖动操作。我们还为RecyclerView设置了一个DragEventListener,并在其中检查拖动事件是否在item内。如果是,则返回true,否则返回false。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值