我正在使用新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
包含的代码Recycler
和SwipeRefreshLayout
.
如果其他人经历过这种行为并解决了它或者至少找到了它的原因?
写下面的代码中addOnScrollListener
的RecyclerView
像这样:
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); } });
在您使用此解决方案之前: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已经发布,到目前为止还没有必要使用此修复程序.
我最近遇到了同样的问题.我尝试了@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); } });
这就是我在我的案例中解决这个问题的方法.对于那些最终在这里寻找与此类似的解决方案的人来说,这可能是有用的.
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); } } });
我希望这肯定可以帮助那些正在寻找类似解决方案的人.