私はScrollListenerでRecyclerViewを使用しています:
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener()
{
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
super.onScrolled(recyclerView, dx, dy);
// Do my logic
}
});
指でスクロールすると、スクロールリスナーが正常にトリガーされました。
しかし、そのように前向きにスクロールすると:
mRecyclerView.scrollToPosition(LAST_POSITION);
スクロールリスナーはトリガーされません。
これは既知の問題です。これは、RecyclerViewがLayoutManagerがスクロールを処理する方法、またはスクロールを処理するかどうかを知らないという事実が原因です。
次のリリースでは、レイアウトの後に最初および/または最後の子の位置が変更された場合にonScrolled
の呼び出しを受け取ります(これは通常、位置へのスクロールの呼び出しの結果です)。
残念ながら、RecyclerViewはscrollTo
リクエストを処理するためにどのくらいのレイアウトマネージャーがスクロールしたか実際にはわからないため、dxとdyは0になります。または、ViewTreeObserverのスクロールコールバックを使用することもできます。
私は同じ問題に直面し、回避策を見つけました。これは、レイアウトマネージャーでsmoothScrollToPositionを使用することです。このメソッドは、スクロールリスナーをトリガーします。だから基本的にこれは私が持っているものです:
recyclerView.scrollToPosition(recyclerAdapter.getItemCount() - 1);
そして今、私はこれに変更しました:
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null, recyclerAdapter.getItemCount() - 1);
それは私にとってはうまく機能しています。
ムイト・リーガル・セウ・コンセルホ。
Button maisOpcoes = (Button) findViewById(R.id.maisOpcoes);
maisOpcoes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null , recyclerViewTmd.getItemCount() - 1);
maisOpcoes.setVisibility(View.GONE);
}
});
少し初歩的ですが、RecyclerViewのこのサブクラスを試すことができます。
public class PatchedRecyclerView extends RecyclerView {
private OnScrollListener listener;
public PatchedRecyclerView(Context context) {
super(context);
}
public PatchedRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PatchedRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setOnScrollListener(OnScrollListener listener) {
super.setOnScrollListener(listener);
this.listener = listener;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int preFirstChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(0)).getPosition() : -1;
int preLastChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(getChildCount() - 1)).getPosition() : -1;
super.onLayout(changed, l, t, r, b);
int postFirstChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(0)).getPosition() : -1;
int postLastChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(getChildCount() - 1)).getPosition() : -1;
// TODO: Insert proper DX and DY values
if (preFirstChildPosition != postFirstChildPosition || preLastChildPosition != postLastChildPosition)
listener.onScrolled(this, 0, 0);
}
}
リサイクラビューでonScrollListenerを明示的にトリガーするには、次を使用します。
recyclerView.smoothScrollBy(x, y);
//x is the horizontal displacement and y is vertical displacement.
int mFirst=0, mLast=0;
recyclerview.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager();
mLast = llm.findLastCompletelyVisibleItemPosition();
mFirst = llm.findFirstCompletelyVisibleItemPosition();
}
});
imgRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager();
llm.scrollToPositionWithOffset(mLast + 1, List.length());
}
});
imgLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager();
llm.scrollToPositionWithOffset(mFirst - 1, List.length());
}
});
してみてください
_LinearLayoutManager.scrollToPositionWithOffset(int, int).
_
LayoutManager.scrollToPosition()
はうまく機能しないかもしれませんが、LinearLayoutManager.scrollToPositionWithOffset()
は機能します。同様に、GridLayoutManagerも同様です。
または、RecyclerViewはLayoutManagerがビューをスクロールする方法を知らないため、カスタムの実装方法を記述する必要があります。
_ class CustomLayoutManager extends LinearLayoutManager{
public void smoothScrollToPosition(RecyclerView recyclerView,
RecyclerView.State state, final int position) {
LinearSmoothScroller smoothScroller =
new LinearSmoothScroller(mContext) {
//Override the methods and write your implementation as per your requirement
//one which controls the direction and another one calculate the speed per Pixel
}
}
_
時々これはトリックをします
_ new Handler().postDelayed(new Runnable() {
@Override
public void run() {
yourList.scrollToPosition(position);
}
}, 200);
_
SmoothScrollToPositionを使用できませんでした(過去にいくつかの問題が発生していました)。最初のアイテムの位置によっては信頼できないように見えたため、 yigit の答え(既にリリースされています)、残念ながら常に機能しませんでした(理由はわかりません)。
そのため、以前にRecyclerViewに追加したスクロールリスナーを使用することになりました。残念ながら、このソリューションの起源は見つかりません。
一定のリスナーが必要な場合、このリスナーを使用する必要はないと思います。幸いなことに、特定の時間にのみ聞く必要があります。
RecyclerViewをオーバーライドします。
public class MyRecyclerView extends RecyclerView {
public interface OnScrollStoppedListener{
void onScrollStopped();
}
private static final int NEW_CHECK_INTERVAL = 100;
private OnScrollStoppedListener mOnScrollStoppedListener;
private Runnable mScrollerTask;
private int mInitialPosition;
public MyRecyclerView(Context context) {
super(context);
init();
}
public MyRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mScrollerTask = new Runnable() {
public void run() {
int newPosition = getScrollY();
if(mInitialPosition - newPosition == 0) {//has stopped
if(mOnScrollStoppedListener !=null) {
mOnScrollStoppedListener.onScrollStopped();
}
} else {
startScrollerTask();
}
}
};
}
public void setOnScrollStoppedListener(MyRecyclerView.OnScrollStoppedListener listener){
mOnScrollStoppedListener = listener;
}
public void startScrollerTask() {
mInitialPosition = getScrollY();
postDelayed(mScrollerTask, NEW_CHECK_INTERVAL);
}
}
使用法:
myRecyclerView.setOnScrollStoppedListener(new MyRecyclerView.OnScrollStoppedListener() {
@Override
public void onScrollStopped() {
// Do your thing
}
});
myRecyclerView.startScrollerTask();