ItemDecoration重写getItemOffsets()和动画

时间:2016-01-03 11:11:57

标签: android android-animation android-recyclerview recycler-adapter

我通过覆盖RecyclerView方法,使用GridLayoutManager向我的getItemOffsets()应用相等的边距(请参阅下面的代码)。

但是,从适配器中删除Object时,将调用删除动画而不使用偏移。因此,anmiation从与要移除的对象不同的位置开始。

我尝试通过getSpanIndex(position)获取位置,但位置(parent.getChildAdapterPosition(view))返回NO_POSITION,因为当调用getItemOffsets()时,对象已从适配器中删除

有没有办法在我的情况下获得补偿?

@Override
public void getItemOffsets(Rect outRect, View view, 
                     RecyclerView parent, RecyclerView.State state) {

    GridLayoutManager mgr = parent.getLayoutManager();
    int position = parent.getChildAdapterPosition(view);

    if (position == RecyclerView.NO_POSITION) {
       // here I need to access the position of the current element
       // and call outRect.set(left, top , right, bottom);
       // which is not possible because it is no longer in the adapter
        return;
    } 

    int spanCount = mgr.getSpanCount();
    int spanSize = mgr.getSpanSizeLookup().getSpanSize(position);
    int spanIndex = mgr.getSpanSizeLookup().getSpanIndex(position, spanCount);

    if (spanIndex == spanCount-1) {
        // last element
        left = space / 2;
        right = space;
    } else if (spanIndex == 0) {
        // first element
        left = space;
        right = space / 2;
    } else {
        // middle element
        left = space / 2;
        right = space / 2;
    }
    outRect.set(left, top, right, bottom);
}

5 个答案:

答案 0 :(得分:4)

尝试使用观看LayoutParams。如果您不使用某些自定义LayoutManager,则应该包含您需要的信息。

int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();

答案 1 :(得分:4)

实际上,从父母那里获得孩子的位置并不是一个好的决定。实际状态可以与实际状态不同,'因为同时工作或者ItemDecorator,或者LayoutManager,或者RecyclerView来规则它们,或者适配器来改变一些元素的位置。

更好的方法,当要求Recycler为您提供特定视图的ViewHolder时。然后你可以得到你需要的全部信息(getLayoutPosition(),getAdapterPosition())。

parent.getChildViewHolder(view).getLayoutPosition();
parent.getChildViewHolder(view).getAdapterPosition;

另一个建议,不是你的情况。如果你需要获得ItemCount,不要使用adapter.getItemCount(),最好是从状态获取,因为Adapter和Recycler中的项目数可以不同。

state.getItemCount()

答案 2 :(得分:2)

因此,在尝试解决这个问题一段时间之后,我最终偶然发现ViewHolder#getOldPosition

javadoc说了以下内容:

  

当LayoutManager支持动画时,RecyclerView会跟踪ViewHolders的3个位置以执行动画。

     

如果在之前的onLayout调用中布置了ViewHolder,旧位置将使其适配器索引保持在先前的布局中。

换句话说,getOldPosition()返回ViewHolder在删除之前所处的适配器位置。

因此,要从ItemDecoration#getItemOffsets方法中获取此值,只需声明:

parent.getChildViewHolder(view).getOldPosition()

我自己测试过,确实有效:)。

答案 3 :(得分:1)

我在这里偶然发现了同样的问题,我已经阅读了答案和讨论。这可能是一个非常晚的答案,但我为了遇到这个问题的其他人而回答。

Julian Os的答案应该被标记为正确的答案,但并没有真正解释过。

这里有详细的解释:

Fn.init(this); ItemDecoration上的

首先获取项目位置 getItemOffsets()正如ilyagorbunov所指出的,这是一种更安全的方式来获得观点的立场。当查询的视图不再存在时,此方法返回parent.getChildViewHolder(view).getAdapterPosition();。因此,如果是这种情况,请检查RecyclerView.NO_POSITION,它返回动画视图的旧位置。当ChildViewHolder不再出现在视图中或已完成动画时,此方法也会返回parent.getChildViewHolder(view).getOldPosition()

如果适配器中有多种视图类型,只需直接从RecyclerView.NO_POSITION获取视图类型

为了完整性,这里有一些代码段:

parent.getChildViewHolder(view).getItemViewType()

答案 4 :(得分:0)

您应该从以下位置获取spanIndex  (view.layoutParams as?GridLayoutManager.LayoutParams)?.spanIndex

和spanSize相同

(view.layoutParams as? GridLayoutManager.LayoutParams)?.spanSize

感谢您在动画制作过程中的安全,因为适配器可能具有一组新数据,而SpanSizeLookup将与您要为其计算偏移量的那些项目在不同的项目集上工作

在项目装饰器中使用适配器不是一个好主意。尝试始终仅根据视图和回收站状态进行所有计算。您可能会考虑通过视图中的标签或处于回收状态的资源传递一些数据。