【问题标题】:RecyclerView Swipe with a view below itRecyclerView 用它下面的视图滑动
【发布时间】:2015-08-26 13:05:40
【问题描述】:

我一直在做一些研究,但我还没有找到一个示例或实现,允许您在滑动时在 RecyclerView 下方放置一个视图(下面的示例图像)。有没有人有任何示例或想法如何不使用使用库来实现。

这是我如何实现滑动关闭。

ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {

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

    @Override
    public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return super.getSwipeDirs(recyclerView, viewHolder);
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        if (viewHolder instanceof ViewDividers) {
            Log.e("DIRECTION", direction + "");
        }
    }
};
new ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recycler);

以下是 Google 收件箱的示例:

【问题讨论】:

  • 你比我晚一天问这个问题真有趣:stackoverflow.com/questions/32204874/…。我尝试在onChildDraw 中绘图,但没有运气。我会看你的问题,希望我们都能解决这个问题,
  • 哈。是的,我会想办法今天。我现在使用刷卡库的方式很崎岖。如果我不能让它以其他方式工作,我会把我拥有的东西发给你。
  • 你有什么运气吗?
  • @spoko 不是我想要的实现方式。我最终使用github.com/daimajia/AndroidSwipeLayout 来实现我想要的滑动。但是您需要在 ViewHolder 中实现滑动
  • 谢谢,那个库部分解决了这个问题。这绝对不是完美的,滑动并不是真正应有的样子(例如,如果您开始向一个方向滑动,则无法向另一个方向滑动),但这是一个好的开始。

标签: android android-recyclerview


【解决方案1】:

我对如何完成此操作的理解是,可以在 xml 中放置两个视图,这些视图将在您的 recyclerview 中每行显示。

例如,这将是我的适配器:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    public static class ExampleViewHolder extends RecyclerView.ViewHolder {
        public TextView background;
        public TextView foreground;

        public ExampleViewHolder(View v) {
            super(v);
            background = (TextView) v.findViewById(R.id.background);
            foreground = (TextView) v.findViewById(R.id.foreground);
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
            if (holder instanceof ExampleViewHolder) {
                ((ExampleViewHolder) holder).background.setBackgroundColor(); // do your manipulation of background and foreground here.
            }
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                          int viewType) {

            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.example, parent, false);
            return new ExampleViewHolder(v);
        }


    }
}

recyclerview 中的每一行都从 R.layout.example 中提取 xml 布局。因此,要在下面创建视图,您可以使用 relativelayout 或 framelayout 将视图创建在另一个之上:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/background"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/foreground"/>
</RelativeLayout>

如果你不想使用库进行滑动,你可以从谷歌复制这个类,然后由 Bruno Romeu Nunes 修改:

https://github.com/heruoxin/Clip-Stack/blob/master/app/src/main/java/com/catchingnow/tinyclipboardmanager/SwipeableRecyclerViewTouchListener.java

该课程将要求您创建一个滑动监听器:

swipeTouchListener =
        new SwipeableRecyclerViewTouchListener(mRecyclerView,
                new SwipeableRecyclerViewTouchListener.SwipeListener() {
                    @Override
                    public boolean canSwipe(int position) {
                        if (position == totalPost.size() - 1 && !connected) {
                            return false;
                        }
                        return true;
                    }

                    @Override
                    public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions) {
                            //change some data if you swipe left
                        }
                        myAdapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions) {
                            //change some data if you swipe right
                        }
                        myAdapter.notifyDataSetChanged();
                    }
                });

然后只需将其与您的回收站视图链接:

    mRecyclerView.addOnItemTouchListener(swipeTouchListener);

【讨论】:

  • 抱歉没有早点回来。我一直忙于工作。我会在上午试一试,然后回复你。
  • Eugene,Touchlistener 对你有用吗?我认为如果您希望顶视图滑动,您只需将其添加到顶视图即可。
  • 我今天将在工作中实现它。我不希望其他人得到答案,因为他显然没有阅读我的问题。但是有一个对那个笔记应用程序的引用,它实现了我正在寻找的东西。如果我有任何问题,介意我回复你吗?
  • 所以我使用了这个实现,但我无法让它在前景视图下显示背景。它允许滑动和关闭前景视图(尽管它总是有一个占位符),但它不会显示背景视图。
  • 我不太确定这将如何工作。当您滑动回收单元格项目时,您正在滑动整个视图而不是框架的顶部。所以你总是会随着前景一起扫掉背景视图。 @Simon 你有这个工作的例子吗?
【解决方案2】:

我正在调查同样的问题。
我最终做的是,在包含 recyclerView 的布局中,我添加了一个简单的FrameLayout,称为“swipe_bg”,与我的RecyclerView.ViewHolder 项目之一高度相同。我将其可见性设置为“已消失”,并将其放在 RecyclerView

然后在我设置ItemTouchHelper 的活动中,我像这样覆盖 onChildDraw..

ItemTouchHelper.SimpleCallback swipeCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT) {

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
         View itemView = viewHolder.itemView;
         Imageview swipe_bg = itemView.findViewById(R.id.imageview_swipe_background);
         swipe_bg.setY(itemView.getTop());
         if (isCurrentlyActive) {
             swipe_bg.setVisibility(View.VISIBLE);
         } else {
             swipe_bg.setVisibility(View.GONE);
         }
         super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }
};

不知道这是否是最好的方法,但似乎是最简单的方法。

【讨论】:

  • 我喜欢它.. 它非常简单的解决方案很棒!
  • 这里如何访问 swipe_bg?
【解决方案3】:

我喜欢@erik 方法,但我建议通过将 Canvas 传递给 onChildDraw() 函数来绘制您想要的内容。例如项目背景或图标。

@Override 
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    final ColorDrawable background = new ColorDrawable(Color.RED);
    background.setBounds(0, itemView.getTop(),   itemView.getLeft() + dX, itemView.getBottom());
    background.draw(c);

    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}

在这种方法中,您将按需绘制所需的内容,而无需膨胀未使用的视图

【讨论】:

  • 这个案例的背景是什么?
  • 背景类型可以是Drawable或者ColorDrawable。
  • 示例中的颜色只有在从左向右滑动时才会显示为红色。对于从右到左,您需要类似 background.setBounds((itemView.getRight()+dX).toInt(), itemView.getTop(), itemView.getRight(), itemView.getBottom()) 和检查如果 dX 值 > 0 或小于 0(告诉您移动方向),您还可以根据需要为每个滑动方向设置不同的颜色
【解决方案4】:

无需分配或在画布上绘制的简单解决方案。 SomeAdapter.SomeVH 应该包含上视图和下视图。通过这种方法,我们将能够只滑动上视图(容器),暴露下视图(带有标签,任何你想要的图标)

class SomeTouchHelper extends ItemTouchHelper.Callback {
...
    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
            float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            if (viewHolder instanceof SomeAdapter.SomeVH) {
                SomeAdapter.SomeVH someViewHolder
                        = (SomeAdapter.SomeVH) viewHolder;
                ViewCompat.setTranslationX(someViewHolder.mContainer, dX);
            }
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    }
...
}

附上

new ItemTouchHelper(SomeTouchHelper).attachToRecyclerView(recyclerView);

不要忘记在适配器 onViewRecycled() 中恢复 SomeVH 的初始视图状态

public void onViewRecycled(final SomeVH holder) {
        if (holder.mContainer != null) {
            holder.mContainer.setTranslationX(0);//restore position
        }
}

【讨论】:

  • 然后告诉我们如何恢复你想出这个方法后的状态
【解决方案5】:

更改 elevation 可以让我将一件物品置于另一件之上。

【讨论】:

    【解决方案6】:

    您可以使用RvTools Library。它将帮助您轻松实现您想要的。

    只需创建具有所需外观的 SwipeContextMenuDrawer

    public class YourSwipeContextMenuDrawer extends SwipeContextMenuDrawer {
    
    private final Paint mRightPaint;
    private final Paint mIconPaint;
    private final Bitmap mRightIconBitmap;
    
    public YourSwipeContextMenuDrawer(@NonNull Context context) {
        mRightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mRightPaint.setColor(ContextCompat.getColor(context, R.color.deep_orange_400));
        mRightIconBitmap = GraphicUtils.getBitmap(context, R.drawable.ic_delete, 100, 100);
        mIconPaint = new Paint();
        mIconPaint.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(context, R.color.backgroundColor), PorterDuff.Mode.SRC_IN));
    }
    
    @Override
    public void drawRight(@NonNull Canvas canvas, @NonNull View view) {
        canvas.drawRect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), mRightPaint);
        canvas.drawBitmap(mRightIconBitmap, view.getLeft() + mRightIconBitmap.getWidth() - 20, (view.getBottom() + view.getTop() - mRightIconBitmap.getHeight()) >> 1, mIconPaint);
    }
    
    @Override
    public void drawLeft(@NonNull Canvas canvas, @NonNull View view) {
    }
    }
    

    并使用滑动操作创建 RvTools 实例并像这样滑动上下文菜单抽屉

     new RvTools.Builder(recyclerView)
                .withSwipeRightAction(this)
                .withSwipeContextMenuDrawer(new YourSwipeContextMenuDrawer(getContext()))
                .buildAndApplyToRecyclerView();
    

    【讨论】:

      猜你喜欢
      • 2017-01-04
      • 1970-01-01
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多