2015-01-07 1 views
20

Я использую RecyclerView, с ScrollListener:RecyclerView scrollToPosition не вызывают scrollListener

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 
     } 
}); 

Когда я прокручивать пальцем, свитка слушатель срабатывает нормально.

Но когда я прокручиваю progrematically, как это:

mRecyclerView.scrollToPosition(LAST_POSITION); 

Свиток слушатель не запускается.

+0

Внутренне он направляет вызов в Менеджер компоновки. Непосредственно попробуйте прокрутить страницу с помощью диспетчера макетов. Прокручивается ли она до ожидаемой позиции? –

+0

Да, 'mRecyclerView.scrollToPosition (LAST_POSITION)' прокручивается до ожидаемой позиции, что вы понимаете, используя диспетчер компоновки? 'mRecyclerView.getLayoutManager(). scrollToPosition (LAST_POSITION)' все еще не вызвал ScrollListener – David

ответ

19

Это известная проблема. Это вызвано тем фактом, что RecyclerView не знает, как LayoutManager будет обрабатывать свиток или если он будет обрабатывать его вообще.

В следующем выпуске вы получите звонок по номеру onScrolled, если первая и последняя дочерняя позиция изменяется после макета (что обычно является результатом вызова прокрутки в позицию).

К сожалению, dx и dy будут равны 0, потому что RecyclerView не знает, сколько макетов было прокручено для обработки запроса scrollTo. Кроме того, вы также можете использовать обратный вызов прокрутки ViewTreeObserver.

+0

:(Спасибо, пожалуйста, дайте образец для этого случая выше? или ссылку для использования обратного вызова прокрутки ViewTreeObserver? – David

+2

Извините, обратный вызов прокрутки VTO не будет работать либо до следующего выпуска: /. Если вам нужно срочное исправление, вы можете переопределить RV, сохранить слушателей в списке, к которому вы можете получить доступ, а затем сообщить им, если первая или последняя дочерняя позиция изменяется после вызова 'onLayout'. – yigit

+0

@yigit любые обновления на этом? У меня такая же проблема, я искал решение, но не нашел его. –

0

Это немного рудиментарное, но вы можете попробовать это подкласс 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); 
    } 
} 
21

Я сталкивался с таким же вопросом и нашел обходной путь, который должен использовать smoothScrollToPosition менеджер компоновки. Этот метод запускает прослушиватель прокрутки. Так что в основном это то, что я использую, чтобы иметь:

recyclerView.scrollToPosition(recyclerAdapter.getItemCount() - 1); 

и теперь я изменил к этому:

recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null, recyclerAdapter.getItemCount() - 1); 

и он работает нормально для меня.

+0

потрясающий, спасибо – smoothumut

+0

отлично, он отлично работает! – Onivas

+0

он не работает на должности 0 –

-1

Muito legal seu conselho.

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); 
      } 
     }); 
+0

пожалуйста, используйте английский –

0
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()); 
    } 
}); 
0

Чтобы явно вызвать onScrollListener над использованием вида ресайклера:

recyclerView.smoothScrollBy(x, y); 
//x is the horizontal displacement and y is vertical displacement. 
0

я не мог использовать 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();