2

此问题已被多次询问,但似乎没有适合我的要求的解决方案。CoordinatorLayout/AppBarLayout干扰RecyclerView scrollToPosition(底部滚动)

我有一个食谱,有说明。每条指令都以RecyclerView排序。顺序必须从上到下。它不能像许多对这个问题的回答一样被扭转。

我有一个添加按钮,当点击一个新的项目被添加到列表的底部。我需要在插入后滚动到新项目。所以我采用按钮的onClick事件下面的代码:

mRecyclerAdapter.addItem(newInstruction); 
mRecyclerView.smoothScrollToPosition(mRecyclerAdapter.getItemCount() - 1); 

这将滚动到倒数第二个项目,因为在适配器的的addItem()方法我有这样的:

mItems.add(item); 
notifyItemInserted(getItemCount() - 1); 

我不t知道notifyItemInserted()调用的细节,但它看起来是在一个单独的线程上,这意味着在插入之后布局视图之前调用smoothScrollToPosition()。因此,它只滚动到倒数第二个项目。

我试过寻找沿onItemInserted行的“回调”功能,但我没有任何运气。例如,没有回答Here

我该如何解决这个问题?

编辑开始

我已经简化了代码,在一个新的项目,希望找到问题,发现了问题所在。当滚动标志被启用时,这似乎是由CoordinatorLayout/AppBarLayout引起的问题。似乎滚动没有考虑到AppBarLayout添加的额外滚动空间。

在下面的示例代码中,如果您禁用应用栏的滚动标志,则滚动到屏幕底部将按预期完美工作。但是,如果启用AppBarLayout滚动行为并更改其高度,则会注意到滚动至底部的高度已关闭。

我需要滚动的行为,所以我怎么让他们很好地玩对方?请注意,我已更改问题以反映问题。

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener { 

    public static final int ITEMS_COUNT = 50; 

    private FloatingActionButton mFloatingActionButton; 
    private RecyclerView mRecyclerView; 
    private RecyclerAdapter mRecyclerAdapter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fabButton); 
     mFloatingActionButton.setOnClickListener(this); 

     setupRecyclerView(); 
    } 

    private void setupRecyclerView() { 
     mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); 
     mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 
     mRecyclerAdapter = new RecyclerAdapter(createItemList()); 
     mRecyclerView.setAdapter(mRecyclerAdapter); 
    } 

    private List<String> createItemList() { 
     List<String> itemList = new ArrayList<>(); 
      for (int i = 0; i < ITEMS_COUNT; i++) { 
       itemList.add("Item " + i); 
      } 
     return itemList; 
    } 

    @Override 
    public void onClick(View v) { 
     mRecyclerView.scrollToPosition(49); 
    } 
} 

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/coordinatorLayout" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/appBarLayout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 

     <!-- changing the height affects the scrolling distance --> 
     <TextView 
      android:layout_width="match_parent" 
      android:layout_height="50dp" 
      android:text="Header" 
      app:layout_scrollFlags="scroll|enterAlways"/> <!-- this is the problem --> 

    </android.support.design.widget.AppBarLayout> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/recyclerView" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     app:layout_behavior="@string/appbar_scrolling_view_behavior"/> 

    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fabButton" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="end|bottom" 
     android:layout_margin="20dp"/> 

</android.support.design.widget.CoordinatorLayout> 

RecyclerAdapter.java

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 

    private List<String> mItemList; 

    public RecyclerAdapter(List<String> itemList) { 
     mItemList = itemList; 
    } 

    @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     Context context = parent.getContext(); 
     View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false); 
     return RecyclerItemViewHolder.newInstance(view); 
    } 

    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 
     RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder; 
     String itemText = mItemList.get(position); 
     holder.setItemText(itemText); 
    } 

    @Override 
    public int getItemCount() { 
     return mItemList == null ? 0 : mItemList.size(); 
    } 

} 

recycler_item。XML

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" 
            xmlns:card_view="http://schemas.android.com/apk/res-auto" 
            android:layout_width="match_parent" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center" 
            android:layout_margin="8dp" 
            card_view:cardCornerRadius="4dp"> 
    <TextView 
     android:id="@+id/itemTextView" 
     android:layout_width="match_parent" 
     android:layout_height="?attr/listPreferredItemHeight" 
     android:gravity="center_vertical" 
     android:padding="8dp" 
     style="@style/Base.TextAppearance.AppCompat.Body2"/> 
</android.support.v7.widget.CardView> 

编辑结束

+0

你的调用顺序是什么。我认为notifyItemInserted(getItemCount() - 1);应该先调用,然后调用smoothScrollToPosition以稍微延迟。 –

+0

你有没有得到任何解决方案。请让我知道这对我们有帮助。我在这里也面临同样的问题。 – Moorthy

回答

2

做一点更多的研究,我发现这个question/answer这有一个解决这个问题的方法。虽然不理想,但现在必须要做。虽然真正的解决方案不应该折叠AppBarLayout,但滚动应该考虑到所需的额外滚动空间。也许这只是一个被忽视的错误。

0

在你的addItem()方法这个变化

notifyItemInserted(getItemCount() - 1); 

notifyItemInserted(mItems.size() - 1); 

这将解决这个问题!

+0

这完全一样。 getItemCount返回mItems.size() – chaser

+0

@chaser Ya没错!我的错。你可以发布你的适配器的代码? –

+0

发布。问题与appbarlayout有关,但我不知道如何解决它。 – chaser

0

添加项目之后添加此

notifyItemRangeChanged(0, items.size()); 
+0

这与notifyItemInserted(getItemCount() - 1)是一样的; – chaser

0

你试过

mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount()); 

你也可以把它放在一个可运行像这样以确保项目已将您滚动到它。

new Handler().postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount()); 
      } 
     }, 1000); 
+0

有趣的是,即使使用Runnable,我也会认为延迟会让RecyclerView滚动到最后......它仍然在做同样的事情。我不明白。我已确定项目数量是最后一项。我甚至调试过它,它绝对是最后一项。我将简化我的代码并将其发布给其他人进行测试。什么是错误的这个scolling bs ... – chaser

+0

我也没有看到你的代码有什么问题,问题在那里,只是你需要努力:) – Max

+0

我做了更多的测试!我在活动开始时添加了20个项目,并且我更改了添加按钮以手动滚动到特定位置。当我在页面底部时,我按下按钮,你知道什么,它滚动到列表顶部就好了。与其他任何数字一样,只要滚动到顶部。但是,一旦滚动需要向下,它只显示前一个项目的1/4。例如,如果我想向下滚动到第10项,我只看到项目9的四分之一。所以它不是位置问题,这是滚动偏移或事端的问题 – chaser

0

在添加列表中Recycleview到适配器通过根据您的需要使用收集方法做一些分类,使用此代码可以帮助你

Comparator<Long> comparator = Collections.reverseOrder(); 
Collections.sort(arrayList, comparator);