RecyclerView Children 计数小于children 的数目
RecyclerView Children count smaller than the number of children
我今天有一个很奇怪的问题:我有一个水平显示一些缩略图的 RecyclerView,我使用 smoothScrollToPosition
导航到我需要的项目,但我注意到一个问题:它不会滚动到最后一项。进一步调试后,我发现我的 recyclerview 比它显示的 children 少!我看到五个项目,一次显示 3 个。但是 children 计数(通过 recyclerView.getChildCount
获得)returns 4 而不是 5,我无法通过 getChildAt(4)
获得最后的 child。更奇怪的是,adapter.getItemCount()
returns 5,而recyclerView.getAdapter().getItemCount()
returns 5...
检查 layoutAdapter
、recyclerView.getLayoutManager().getItemCount()
returns 5 和`recyclerView..getLayoutManager().getChildCount() returns 4...
我需要两件事:首先,我需要我的 recyclerView 滚动到最后一项,其次:我需要能够获得所有 children ,因为我在用户与项目交互时对它们进行了一些修改。
一些代码:
// 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) 要滚动到列表中的某个位置,您可以使用 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)仅绘制屏幕上可见的项目 + 顶部和底部的一个或两个缓冲区以使滚动看起来不错。当您滚动时,它将 "recycle" 视图并使用来自您的适配器的数据填充它们。因此,滚动到顶部的视图将在列表底部重新使用,数据来自下一个项目。
因此,您无法同时获取适配器中项目的所有视图。但是,您可以获取适配器中的所有项目,修改它们,然后触发适配器使用 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)。
我今天有一个很奇怪的问题:我有一个水平显示一些缩略图的 RecyclerView,我使用 smoothScrollToPosition
导航到我需要的项目,但我注意到一个问题:它不会滚动到最后一项。进一步调试后,我发现我的 recyclerview 比它显示的 children 少!我看到五个项目,一次显示 3 个。但是 children 计数(通过 recyclerView.getChildCount
获得)returns 4 而不是 5,我无法通过 getChildAt(4)
获得最后的 child。更奇怪的是,adapter.getItemCount()
returns 5,而recyclerView.getAdapter().getItemCount()
returns 5...
检查 layoutAdapter
、recyclerView.getLayoutManager().getItemCount()
returns 5 和`recyclerView..getLayoutManager().getChildCount() returns 4...
我需要两件事:首先,我需要我的 recyclerView 滚动到最后一项,其次:我需要能够获得所有 children ,因为我在用户与项目交互时对它们进行了一些修改。
一些代码:
// 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) 要滚动到列表中的某个位置,您可以使用 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)仅绘制屏幕上可见的项目 + 顶部和底部的一个或两个缓冲区以使滚动看起来不错。当您滚动时,它将 "recycle" 视图并使用来自您的适配器的数据填充它们。因此,滚动到顶部的视图将在列表底部重新使用,数据来自下一个项目。
因此,您无法同时获取适配器中项目的所有视图。但是,您可以获取适配器中的所有项目,修改它们,然后触发适配器使用 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)。