RecyclerView和SwipeRefreshLayout

 Twosssss 发布于 2022-12-29 16:33

我正在使用新RecyclerView-Layout的a SwipeRefreshLayout并经历了一种奇怪的行为.当滚动列表回到顶部时,有时顶部的视图会被切入.

列表滚动到顶部

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

切割的行

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

 

    


这是我的布局 - 行由RecyclerViewAdapter动态构建(此列表中有2个Viewtypes).

public class HotRecyclerAdapter extends TikDaggerRecyclerAdapter {

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.

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

4 个回答
  • 写下面的代码中addOnScrollListenerRecyclerView

    像这样:

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                int topRowVerticalPosition =
                        (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
                swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
    
            }
    
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }
        });
    

    2022-12-29 16:34 回答
  • 在您使用此解决方案之前:RecyclerView尚未完成,请不要在生产中使用它,除非您喜欢我!

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

    解决方案的下降:

    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已经发布,到目前为止还没有必要使用此修复程序.

    2022-12-29 16:34 回答
  • 我最近遇到了同样的问题.我尝试了@Krunal_Patel建议的方法,但它在我的Nexus 4中大部分时间工作,并且在三星galaxy s2中根本不起作用.在调试时,对于RecyclerView,recyclelerView.getChildAt(0).getTop()始终不正确.因此,在经过各种方法之后,我想我们可以利用LayoutManager的方法findFirstCompletelyVisibleItemPosition()来预测RecyclerView的第一项是否可见,以启用SwipeRefreshLayout.Find下面的代码.希望它可以帮助有人试图解决同样的问题.干杯.

        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            }
    
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
            }
        });
    

    2022-12-29 16:36 回答
  • 这就是我在我的案例中解决这个问题的方法.对于那些最终在这里寻找与此类似的解决方案的人来说,这可能是有用的.

    recyclerView.addOnScrollListener(new OnScrollListener()
        {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                // TODO Auto-generated method stub
                super.onScrolled(recyclerView, dx, dy);
            }
    
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState)
            {
                // TODO Auto-generated method stub
                //super.onScrollStateChanged(recyclerView, newState);
                int firstPos=linearLayoutManager.findFirstCompletelyVisibleItemPosition();
                if (firstPos>0)
                {
                    swipeLayout.setEnabled(false);
                }
                else {
                    swipeLayout.setEnabled(true);
                }
            }
        });
    

    我希望这肯定可以帮助那些正在寻找类似解决方案的人.

    2022-12-29 16:39 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有