RecyclerView 和 SwipeRefreshLayout

新手上路,请多包涵

我在 RecyclerView-Layout 中使用新的 SwipeRefreshLayout 并遇到了奇怪的行为。当将列表滚动回顶部时,有时顶部的视图会被切入。

列表滚动到顶部

如果我现在尝试滚动到顶部 - Pull-To-Refresh 触发器。

切割行

如果我尝试删除 Recycler-View 周围的 Swipe-Refresh-Layout,问题就消失了。并且它可以在任何手机上重现(不仅是 L-Preview 设备)。

  <android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/contentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/hot_fragment_recycler"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.v4.widget.SwipeRefreshLayout>

这是我的布局 - 行是由 RecyclerViewAdapter 动态构建的(此列表中有 2 个视图类型)。

 public class HotRecyclerAdapter extends TikDaggerRecyclerAdapter<GameRow> {

private static final int VIEWTYPE_GAME_TITLE = 0;
private static final int VIEWTYPE_GAME_TEAM = 1;

@Inject
Picasso picasso;

public HotRecyclerAdapter(Injector injector) {
    super(injector);
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position, int viewType) {
    switch (viewType) {
        case VIEWTYPE_GAME_TITLE: {
            TitleGameRowViewHolder holder = (TitleGameRowViewHolder) viewHolder;
            holder.bindGameRow(picasso, getItem(position));
            break;
        }
        case VIEWTYPE_GAME_TEAM: {
            TeamGameRowViewHolder holder = (TeamGameRowViewHolder) viewHolder;
            holder.bindGameRow(picasso, getItem(position));
            break;
        }
    }
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    switch (viewType) {
        case VIEWTYPE_GAME_TITLE: {
            View view = inflater.inflate(R.layout.game_row_title, viewGroup, false);
            return new TitleGameRowViewHolder(view);
        }
        case VIEWTYPE_GAME_TEAM: {
            View view = inflater.inflate(R.layout.game_row_team, viewGroup, false);
            return new TeamGameRowViewHolder(view);
        }
    }
    return null;
}

@Override
public int getItemViewType(int position) {
    GameRow row = getItem(position);
    if (row.isTeamGameRow()) {
        return VIEWTYPE_GAME_TEAM;
    }
    return VIEWTYPE_GAME_TITLE;
}

这是适配器。

    hotAdapter = new HotRecyclerAdapter(this);

    recyclerView.setHasFixedSize(false);
    recyclerView.setAdapter(hotAdapter);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

    contentView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            loadData();
        }
    });

    TypedArray colorSheme = getResources().obtainTypedArray(R.array.main_refresh_sheme);
    contentView.setColorSchemeResources(colorSheme.getResourceId(0, -1), colorSheme.getResourceId(1, -1), colorSheme.getResourceId(2, -1), colorSheme.getResourceId(3, -1));

以及 Fragment 的代码包含 RecyclerSwipeRefreshLayout

如果其他人经历过这种行为并解决了它,或者至少找到了原因?

原文由 Lukas Olsen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 410
2 个回答

在您使用此解决方案之前:RecyclerView 尚未完成,除非您像我一样,否则尽量不要在生产中使用它!

至于 2014 年 11 月,RecyclerView 中仍然存在会导致 canScrollVertically 过早返回 false 的错误。此解决方案将解决所有滚动问题。

溶液中的下降:

 public class FixedRecyclerView extends RecyclerView {
    public FixedRecyclerView(Context context) {
        super(context);
    }

    public FixedRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean canScrollVertically(int direction) {
        // check if scrolling up
        if (direction < 1) {
            boolean original = super.canScrollVertically(direction);
            return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original;
        }
        return super.canScrollVertically(direction);

    }
}

您甚至不需要将代码中的 --- 替换为 RecyclerView FixedRecyclerView ,替换 XML 标记就足够了! (确保当 RecyclerView 完成时,转换将快速而简单)

解释:

基本上, canScrollVertically(boolean) 返回 false,所以我们检查 RecyclerView 是否一直滚动到第一个视图的顶部(第一个孩子的顶部为 0)然后返回。

编辑:如果你不想扩展 RecyclerView 出于某种原因,你可以扩展 SwipeRefreshLayout 并覆盖 canChildScrollUp() 方法并将检查逻辑放在那里.

EDIT2:RecyclerView 已经发布,到目前为止没有必要使用这个修复。

原文由 tom91136 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果您使用没有滚动视图的 recyclerview,您可以这样做,它会起作用

        recyclerview.isNestedScrollingEnabled = true

原文由 Rohan majhi 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题