RecyclerView儿童数量小于儿童数量

时间:2016-07-22 23:53:27

标签: android android-recyclerview android-support-library

今天我有一个非常奇怪的问题:我有一个水平显示一些缩略图的RecyclerView,我使用smoothScrollToPosition导航到我需要的项目,但我注意到一个问题:它不会滚动到最后项目。经过进一步的调试,我发现我的recyclerview比显示的孩子少!我看到五个项目,一次显示3个。但是孩子数量(得到recyclerView.getChildCount)返回4而不是5,我无法得到getChildAt(4)的最后一个孩子。更奇怪的是,adapter.getItemCount()返回5,recyclerView.getAdapter().getItemCount()返回5 ...

在检查layoutAdapter时,recyclerView.getLayoutManager().getItemCount()返回5,并且`recyclelerView..getLayoutManager()。getChildCount()返回4 ......

我需要两件事:首先,我需要我的recyclerView滚动到最后一项,第二:我需要能够得到所有孩子,因为我对它们做了一些修改,因为用户与项目互动。

一些代码:

// Scrolling and editing the item inside the recyclerView
// It doesn't scroll to position 4, even having a item there...
mLayoutManager.smoothScrollToPosition(recyclerView, null, position);

// the code bellow returns null if position = 4, even if the recyclerView adapter has a item at index 4, and it is visible...
ImageView iv = (ImageView) recyclerView.getChildAt(position);
if (iv != null) {
    iv.setPadding(10, 10, 10, 10);
    iv.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
    ImageView ivo = (ImageView) recyclerView.getChildAt(position - 1);
    if (position - 1 == 0) {
        ivo.setPadding(10, 10, 10, 10);
    } else {
        ivo.setPadding(0, 10, 10, 10);
    }
    ivo.setBackgroundColor(getResources().getColor(R.color.transparent));
}

smoothScrollToPosition实现:

public class SnappingLinearLayoutManager extends LinearLayoutManager {

    private static final float MILLISECONDS_PER_INCH = 150f;

    public SnappingLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext()){
            @Override
            public PointF computeScrollVectorForPosition(int targetPosition) {
                return new PointF(0, 1);
            }

            //This returns the milliseconds it takes to scroll one pixel.
            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
            }
        };
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return SnappingLinearLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_ANY;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

1)要滚动到列表中的某个位置,您可以使用scrollToPosition(position)。您传入的位置将是最后一项的索引,如下所示:

recyclerView.smoothScrollToPosition(adapter.getItemCount())

我能够使用v7 RecyclerView和android的LinearLayoutManager来实现这种方法。

的build.gradle

...
dependencies {
    ...
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:recyclerview-v7:23.4.0'
    ...
}

RecyclerView布局代码:

<android.support.v7.widget.RecyclerView android:id="@+id/item_list"
  android:name="fbalashov.spikeapp.ItemListFragment"
  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="match_parent"
  app:layoutManager="LinearLayoutManager" />

然后,当我想滚动到列表顶部时,我只需调用我的scrollToBottom方法:

private void scrollToBottom() {
  recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount());
}

这会使RecyclerView平滑地滚动到列表中的最后一项。

2)正如Rafal所说,RecyclerView(和ListView)只绘制屏幕上可见的项目+顶部和底部的一个或两个缓冲区,使滚动看起来不错。当你滚动时,它会&#34;回收&#34;视图并使用适配器中的数据填充它们。因此,从顶部滚动的视图将在列表的底部重新使用,数据将形成下一个项目。

因此,您无法同时获取适配器中项目的所有视图。但是,您可以获取适配器中的所有项目,修改它们,然后使用adapter.notifyDataSetChanged()触发适配器重新绘制recyclerView中的视图。例如:

// getItems() is a method you will have to add to you adapter to get the items from your 
// adapter. Otherwise you can add a method in your adapter to update the items.
List<DataType> items = adapter.getItems();
for (DataType item : items) {
  // make some change to each item
}
// this will force the recycler view to redraw its views
adapter.notifyDataSetChanged();

您还可以通过更新适配器中的这些项目并使用notifyItemChanged(position),对适配器中的项目进行更有针对性的更改。