首页 文章

替换RecyclerView的数据集时出现问题

提问于
浏览
-1

我正在开发一个显示网站图像的应用程序 . 图像都具有不同的高度,它们显示的视图(视图)也是如此 .

应用过滤器时,通过直接从适配器清除它们来删除先前的数据集(因此,当前可见的数据集) . 将适配器通知适配器

final int removedSize = items.size();
items.clear();
notifyItemRangeRemoved(0, removedSize);

这使旧项目在屏幕上显示动画 . 当该动画结束时,我使用添加新数据集

RecyclerView attachedView;

attachedView.getItemAnimator().isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() { // Add a listener to listen when the new items should be added
            @Override
            public void onAnimationsFinished() {
                attachedView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        addPhotosList(objects);
                        notifyItemRangeChanged(0, objects.size());                            
                        loading = false;
                        attachedView.requestLayout();
                    }
                },700);
            }
        });

这会动画添加的项目 . 奇怪的是,我有时会在RecyclerView内部出现空白,就好像RecyclerView在绘制所有项目时不会将ViewHolder的新维度考虑在内 . 更重要的是,有些物品实际上是相互叠加的,只要他们愿意,它们就会闪现在前景中 . 放置在正确位置的物品顶部的物品是应放置在间隙内的物品 . 他们不会回到差距,但在手动调查项目集时,我注意到他们应该在那里 .

RecyclerView是SwipeRefreshLayout视图的子代,但我不认为这应该是一个问题 .

我设置为RecyclerView的一些参数:

recents.setLayoutManager(layoutManager);
recents.setHasFixedSize(false);
recents.setItemViewCacheSize(100);

在布局文件中

android:animationCache="false"
android:scrollingCache="false"

我究竟做错了什么?

我已经添加了0.7秒的小延迟以确保所有动画都已完成,但这似乎没有太大帮助 .

ItemAnimator:

@Override
    public boolean animateAdd(RecyclerView.ViewHolder viewHolder) {
        if (viewHolder.getItemViewType() != -8) { // ImageAdapter.ViewType.EMPTY = -8;
            if (viewHolder.getLayoutPosition() > lastAddAnimatedItem) {
                lastAddAnimatedItem++;
                runEnterAnimation((ImageListView) viewHolder, viewHolder.getLayoutPosition());
                return false;
            }
        }
        lastAddAnimatedItem = -6;
        dispatchAddFinished(viewHolder);
        return false;
    }

    @Override
    public boolean animateRemove(RecyclerView.ViewHolder viewHolder) {
        if (viewHolder.getItemViewType() != -8) { // ImageAdapter.ViewType.EMPTY = -8;
            if (viewHolder.getLayoutPosition() > lastRemoveAnimatedItem) {
                lastRemoveAnimatedItem++;
                runExitAnimation((ImageListView) viewHolder, viewHolder.getLayoutPosition());
                return false;
            }
        }

        lastRemoveAnimatedItem = -6;
        dispatchRemoveFinished(viewHolder);
        return false;
    }

    private void runEnterAnimation(final ImageListView holder, int position) {
        final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext());
        holder.itemView.setTranslationY(screenHeight + holder.itemView.getHeight());
        holder.itemView.animate()
                .translationY(0)
                .setStartDelay(150 + (20 * (position)))
                .setInterpolator(new DecelerateInterpolator(3.f))
                .setDuration(700)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        dispatchAddFinished(holder);
                    }
                })
                .start();
    }

    private void runExitAnimation(final ImageListView holder, int position) {
        final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext());
        holder.itemView.setTranslationY(0);
        holder.itemView.animate()
                .translationY(-screenHeight - holder.itemView.getHeight())
                .setStartDelay(Math.abs(20 * (position)))
                .setInterpolator(new DecelerateInterpolator(3.f))
                .setDuration(700)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        dispatchRemoveFinished(holder);
                    }
                })
                .start();
    }

编辑:

看来屏幕上 last visible 项目之后的 first 项目放在错误的位置 .

1 回答

  • 1

    我已经和这个问题争了一个多星期了,但我找到了解决方案:

    将runEnterAnimation更改为:

    private void runEnterAnimation(final ImageListView holder, int position) {
            final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext());
            holder.itemView.setTranslationY(screenHeight);
            holder.itemView.animate()
                    .translationY(0)
                    .setStartDelay(150 + (20 * (position)))
                    .setInterpolator(new DecelerateInterpolator(3.f))
                    .setDuration(700)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            dispatchAddFinished(holder);
                            holder.itemView.setTranslationY(0f);
                        }
                        @Override
                        public void onAnimationCancel(Animator animation){
                            holder.itemView.setTranslationY(0f);
                        }
                    })
                    .start();
        }
    

    注意onAnimationEnd和onAnimationCancel回调中的新行,这可以确保项目的转换始终设置为动画动画所需的转换 .

    用此替换runExitAnimation:

    private void runExitAnimation(final ImageListView holder, int position) {
            final int screenHeight = Utils.getScreenHeight(holder.itemView.getContext());
            holder.itemView.setTranslationY(0);
            holder.itemView.animate()
                    .translationY(-screenHeight)
                    .setStartDelay(Math.abs(20 * (position)))
                    .setInterpolator(new DecelerateInterpolator(3.f))
                    .setDuration(700)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            dispatchRemoveFinished(holder);
                            holder.itemView.setTranslationY(-screenHeight);
                        }
                        @Override
                        public void onAnimationCancel(Animator animation){
                            holder.itemView.setTranslationY(-screenHeight);
                        }
                    })
                    .start();
        }
    

    将endAnimation替换为:

    @Override
        public void endAnimation(RecyclerView.ViewHolder item) {
            super.endAnimation(item);
            item.itemView.setTranslationY(0f);
        }
    

    这将确保持有者始终返回其原始位置 .

    在适配器中,将以下行添加到onBindViewHolder方法:

    holder.itemView.setTranslationY(0f);
    

    在上面这一行中,我得到了另一个数据集的第一项被困在后台的奇怪错误,但是如果你将与RecyclerView背景颜色相同的背景添加到你的项目中,那么bug也是固定的 .

    有时候把事情写下去看是非常有用的 . 就像这次它指出了解决方案 .

相关问题