Подтвердить что ты не робот

RecyclerView Swipe с изображением под ним

Я занимаюсь некоторыми исследованиями, и мне еще предстоит найти пример или реализацию, которая позволяет вам отображать представление (пример ниже) под 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 Inbox: введите описание изображения здесь

4b9b3361

Ответ 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 вытаскивает макет xml из R.layout.example. Поэтому, чтобы создать представление под ним, вы можете просто использовать 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>

Затем, если вы не хотите использовать библиотеку для прокрутки, вы можете скопировать этот класс из google и впоследствии изменить 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();
                    }
                });

Затем просто привяжите его к вашему recyclerview:

    mRecyclerView.addOnItemTouchListener(swipeTouchListener);

Ответ 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;
         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);
    }
};

Не знаю, лучший ли это способ, но казался самым простым способом.

Ответ 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);
}

В этом подходе вы будете рисовать то, что нужно по требованию, и не нужно раздувать неиспользуемые виды

Ответ 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);

не забудьте восстановить начальное состояние просмотра SomeVH в адаптере onViewRecycled()

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

Ответ 5

Вы можете использовать Библиотека RvTools. Это поможет вам легко реализовать то, что вы хотите.

Просто создайте свой 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();