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

Как скрыть разделитель, когда удаление анимации происходит в режиме просмотра recycler

RecyclerView по умолчанию, имеет приятную анимацию удаления, если вы setHasStableIds(true) и обеспечиваете правильную реализацию на getItemId.

Недавно я добавил разделитель в RecyclerView через qaru.site/info/12338/...

Результат выглядит следующим образом

https://www.youtube.com/watch?v=u-2kPZwF_0w

https://youtu.be/c81OsFAL3zY (Чтобы сделать разделители более заметными при воспроизведении анимации, я временно меняю фон RecyclerView на красный)

Разделители все еще видны при воспроизведении анимации удаления.

Однако, если я посмотрю пример GMail, при воспроизведении анимации удаления, разделительные линии больше не видны. Они покрыты сплошной цветной областью.

https://www.youtube.com/watch?v=cLs7paU-BIg

Могу ли я узнать, как я могу добиться такого же эффекта, как GMail, не отображая разделительные линии, когда воспроизводится анимация удаления?

4b9b3361

Ответ 1

Решение довольно просто. Чтобы анимировать украшение, вы можете и должны использовать view.getTranslation_() и view.getAlpha(). Я написал сообщение в блоге некоторое время назад по этой точной проблеме, вы можете прочитать его здесь.

Перевод и исчезновение

Менеджер компоновки по умолчанию будет исчезать (альфа) и переводить их, когда они будут добавлены или удалены. Вы должны учитывать это в своем оформлении.

Идея проста:

Однако вы рисуете свое украшение, применяете ту же букву и перевод на свой рисунок, используя view.getAlpha() и view.getTranslationY().

После вашего связанного ответа его нужно будет адаптировать следующим образом:

// translate
int top = child.getBottom() + params.bottomMargin + view.getTranslationY();
int bottom = top + mDivider.getIntrinsicHeight();

// apply alpha
mDivider.setAlpha((int) child.getAlpha() * 255f);
mDivider.setBounds(left + view.getTranslationX(), top,
        right + view.getTranslationX(), bottom);
mDivider.draw(c);

Полный образец

Мне нравится рисовать вещи сами, так как я думаю, что рисование линии меньше накладных расходов, чем макетирование drawable, это будет выглядеть следующим образом:

public class SeparatorDecoration extends RecyclerView.ItemDecoration {

    private final Paint mPaint;
    private final int mAlpha;

    public SeparatorDecoration(@ColorInt int color, float width) {
        mPaint = new Paint();
        mPaint.setColor(color);
        mPaint.setStrokeWidth(width);
        mAlpha = mPaint.getAlpha();
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();

        // we retrieve the position in the list
        final int position = params.getViewAdapterPosition();

        // add space for the separator to the bottom of every view but the last one
        if (position < state.getItemCount()) {
            outRect.set(0, 0, 0, (int) mPaint.getStrokeWidth()); // left, top, right, bottom
        } else {
            outRect.setEmpty(); // 0, 0, 0, 0
        }
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        // a line will draw half its size to top and bottom,
        // hence the offset to place it correctly
        final int offset = (int) (mPaint.getStrokeWidth() / 2);

        // this will iterate over every visible view
        for (int i = 0; i < parent.getChildCount(); i++) {
            final View view = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();

            // get the position
            final int position = params.getViewAdapterPosition();

            // and finally draw the separator
            if (position < state.getItemCount()) {
                // apply alpha to support animations
                mPaint.setAlpha((int) (view.getAlpha() * mAlpha));

                float positionY = view.getBottom() + offset + view.getTranslationY();
                // do the drawing
                c.drawLine(view.getLeft() + view.getTranslationX(),
                        positionY,
                        view.getRight() + view.getTranslationX(),
                        positionY,
                        mPaint);
            }
        }
    }
}

Ответ 2

Во-первых, извините за массивный размер ответа. Тем не менее, я счел необходимым включить всю свою тестовую активность, чтобы вы могли видеть, что я сделал.

Проблема

Проблема, которая у вас есть, заключается в том, что DividerItemDecoration не имеет представления о состоянии вашей строки. Он не знает, удаляется ли элемент.

По этой причине я сделал POJO, который мы можем использовать, чтобы содержать целое число (которое мы используем как itemId, так и визуальное представление и boolean, указывающий, что эта строка удаляется или нет.

Когда вы решили удалить записи (в этом примере adapter.notifyItemRangeRemoved(3, 8);), вы также должны установить связанный Pojo для удаления (в этом примере pojo.beingDeleted = true;).

Положение разделителя при его удалении составляет reset для цвета родительского представления. Чтобы скрыть разделитель.

Я не очень люблю использовать сам набор данных для управления состоянием своего родительского списка. Возможно, лучший способ.

Результат визуализируется

Удаление элементов и их разделителей

Деятельность:

public class MainActivity extends AppCompatActivity {
    private static final int VERTICAL_ITEM_SPACE = 8;

    private List<Pojo> mDataset = new ArrayList<Pojo>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for(int i = 0; i < 30; i++) {
            mDataset.add(new Pojo(i));
        }

        final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
        recyclerView.addItemDecoration(new DividerItemDecoration(this));

        RecyclerView.ItemAnimator ia = recyclerView.getItemAnimator();
        ia.setRemoveDuration(4000);

        final Adapter adapter = new Adapter(mDataset);
        recyclerView.setAdapter(adapter);

        (new Handler(Looper.getMainLooper())).postDelayed(new Runnable() {
            @Override
            public void run() {
                int index = 0;
                Iterator<Pojo> it = mDataset.iterator();
                while(it.hasNext()) {
                    Pojo pojo = it.next();

                    if(index >= 3 && index <= 10) {
                        pojo.beingDeleted = true;
                        it.remove();
                    }

                    index++;
                }

                adapter.notifyItemRangeRemoved(3, 8);
            }
        }, 2000);
    }

    public class Adapter extends RecyclerView.Adapter<Holder> {
        private List<Pojo> mDataset;

        public Adapter(@NonNull final List<Pojo> dataset) {
            setHasStableIds(true);
            mDataset = dataset;
        }

        @Override
        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_cell, parent, false);
            return new Holder(view);
        }

        @Override
        public void onBindViewHolder(final Holder holder, final int position) {
            final Pojo data = mDataset.get(position);

            holder.itemView.setTag(data);
            holder.textView.setText("Test "+data.dataItem);
        }

        @Override
        public long getItemId(int position) {
            return mDataset.get(position).dataItem;
        }

        @Override
        public int getItemCount() {
            return mDataset.size();
        }
    }

    public class Holder extends RecyclerView.ViewHolder {
        public TextView textView;

        public Holder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.text);
        }
    }

    public class Pojo {
        public int dataItem;
        public boolean beingDeleted = false;

        public Pojo(int dataItem) {
            this.dataItem = dataItem;
        }
    }

    public class DividerItemDecoration extends RecyclerView.ItemDecoration {

        private final int[] ATTRS = new int[]{android.R.attr.listDivider};

        private Paint mOverwritePaint;
        private Drawable mDivider;

        /**
         * Default divider will be used
         */
        public DividerItemDecoration(Context context) {
            final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
            mDivider = styledAttributes.getDrawable(0);
            styledAttributes.recycle();
            initializePaint();
        }

        /**
         * Custom divider will be used
         */
        public DividerItemDecoration(Context context, int resId) {
            mDivider = ContextCompat.getDrawable(context, resId);
            initializePaint();
        }

        private void initializePaint() {
            mOverwritePaint = new Paint();
            mOverwritePaint.setColor(ContextCompat.getColor(MainActivity.this, android.R.color.background_light));
        }

        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            int left = parent.getPaddingLeft();
            int right = parent.getWidth() - parent.getPaddingRight();

            int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = parent.getChildAt(i);

                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

                int top = child.getBottom() + params.bottomMargin;
                int bottom = top + mDivider.getIntrinsicHeight();

                Pojo item = (Pojo) child.getTag();
                if(item.beingDeleted) {
                    c.drawRect(left, top, right, bottom, mOverwritePaint);
                } else {
                    mDivider.setBounds(left, top, right, bottom);
                    mDivider.draw(c);
                }

            }
        }
    }

    public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {

        private final int mVerticalSpaceHeight;

        public VerticalSpaceItemDecoration(int mVerticalSpaceHeight) {
            this.mVerticalSpaceHeight = mVerticalSpaceHeight;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                                   RecyclerView.State state) {
            outRect.bottom = mVerticalSpaceHeight;
        }
    }
}

Макет действий

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:background="@android:color/background_light"
    tools:context="test.dae.myapplication.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

Схема "строка" RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:id="@+id/text"
          android:padding="8dp">

</TextView>

Ответ 3

Я думаю, что ItemDecorator, который вы используете, чтобы нарисовать разделитель после того, как каждая строка запуталась, когда выполняется удаление, удаляется.

Вместо того, чтобы использовать ItemDecorator для рисования разделителя в recyclerview, добавьте представление в конец вашего макета детского макета RecyclerView, который будет рисовать разделительную линию, например ItemDecorator.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
 <!-- child layout Design !-->

 <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@android:color/darker_gray"
        android:layout_gravity="bottom"
        />
 </Linearlayout>