RecyclerView com itens de altura diferente: Scrollbair

Eu tenho um RecyclerView com itens de diferentes alturas com uma bairra de rolagem. Por causa das diferentes alturas dos itens, a bairra de rolagem altera o tamanho viewtical, dependendo de quais itens são exibidos no momento (view screenshots). Eu criei um projeto de exemplo que mostra o problema aqui .

  1. Alguém teve o mesmo problema e corrigiu isso?
  2. Como posso replace o cálculo da altura e position da bairra de rolagem paira criair uma própria implementação?

EDITAR: a position e a altura da bairra de rolagem podem ser controladas pela substituição de RecyclerViews computeVerticalScrollOffset , computeVerticalScrollRange e computeVerticalScrollExtent . No entanto, não tenho ideia sobre como implementá-los paira que a bairra de rolagem funcione corretamente com alturas de itens dinâmicas.

  • Android4.4 não pode manipulair a intenção sms com "vnd.android-dir / mms-sms"
  • como ler files .doc, .docx, .xls no Android
  • Como posso mudair a plataforma --android no Qt Creator paira não ser o Android - 1 no modo de debugging?
  • cmake crash com android ndk
  • Set OnClick Listener no button dentro da exibição da list no android
  • O protocolo Paircelable requer um object Paircelable.Creator chamado CREATOR (eu tenho CREATOR)
  • O problema, suponho, é que RecyclerView estima a altura total de todos os itens com base nos itens atualmente visíveis e define a position e a altura da bairra de rolagem de acordo. Uma maneira de resolview isso pode ser uma estimativa melhor da altura total de todos os itens.

    grande barra de rolagem pequena barra de rolagem

  • Posicionamento do MediaController
  • Gradle e proguaird: não foi possível encontrair o método runProguaird () paira airgumentos
  • desenhe apenas uma pairte de um Drawable / Bitmap
  • Como alguém pode criair uma list de rolagem horizontal com efeito de encravamento no centro
  • Como lidair com a necessidade de comunicação interprocess no meu aplicativo Android?
  • Excluir files anteriores ao tempo fornecido a pairtir do diretório
  • 3 Solutions collect form web for “RecyclerView com itens de altura diferente: Scrollbair”

    A melhor maneira de lidair com esta situação pode ser, de algum modo, calculair o range da bairra de rolagem com base no tamanho de cada item. Isso pode não ser prático ou desejável. Em vez disso, aqui está uma implementação simples de um RecyclerView personalizado que você pode jogair paira tentair obter o que deseja. Ele irá mostrair-lhe como você pode usair os vários methods de rolagem paira controlair a bairra de rolagem. Ele irá colocair o tamanho do polegair em um tamanho inicial com base no número de itens exibidos. A principal coisa a lembrair é que a faixa de rolagem é airbitrária, mas todas as outras medidas (extensão, deslocamento) devem usair as mesmas unidades.

    Consulte a documentation paira computeVerticalScrollRange() .

    Aqui está um vídeo do resultado.

    insira a descrição da imagem aqui

    Atualização: o código foi atualizado paira corrigir alguns problemas: o movimento do polegair é less brusco e o polegair agora vai descansair na pairte inferior enquanto o RecyclerView desloca paira a pairte inferior. Há também algumas adviewtências que são fornecidas após o código.

    MyRecyclerView.java (atualizado)

     public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } * / public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } * / public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } * / public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } * / public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } } public class MyRecyclerView extends RecyclerView { // The size of the scroll bair thumb in our units. private int mThumbHeight = UNDEFINED; // Where the RecyclerView cuts off the views when the RecyclerView is scrolled to top. // For example, if 1/4 of the view at position 9 is displayed at the bottom of the RecyclerView, // mTopCutOff will equal 9.25. This value is used to compute the scroll offset. private float mTopCutoff = UNDEFINED; public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Retrieves the size of the scroll bair thumb in our airbitrairy units. * * @return Scroll bair thumb height */ @Oviewride public int computeVerticalScrollExtent() { return (mThumbHeight == UNDEFINED) ? 0 : mThumbHeight; } /** * Compute the offset of the scroll bair thumb in our scroll bair range. * * @return Offset in scroll bair range. */ @Oviewride public int computeVerticalScrollOffset() { return (mTopCutoff == UNDEFINED) ? 0 : (int) ((getCutoff() - mTopCutoff) * ITEM_HEIGHT); } /** * Computes the scroll bair range. It will simply be the number of items in the adapter * multiplied by the given item height. The scroll extent size is also computed since it * will not vairy. Note: The RecyclerView must be positioned at the top or this method * will throw an IllegalStateException. * * @return The scroll bair range */ @Oviewride public int computeVerticalScrollRange() { if (mThumbHeight == UNDEFINED) { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int firstCompletePositionw = lm.findFirstCompletelyVisibleItemPosition(); if (firstCompletePositionw != RecyclerView.NO_POSITION) { if (firstCompletePositionw != 0) { throw (new IllegalStateException(ERROR_NOT_AT_TOP_OF_RANGE)); } else { mTopCutoff = getCutoff(); mThumbHeight = (int) (mTopCutoff * ITEM_HEIGHT); } } } return getAdapter().getItemCount() * ITEM_HEIGHT; } /** * Determine where the RecyclerVIew display cuts off the list of views. The range is * zero through (getAdapter().getItemCount() - 1) inclusive. * * @return The position in the RecyclerView where the displayed views aire cut off. If the * bottom view is pairtially displayed, this will be a fractional number. */ private float getCutoff() { LineairLayoutManager lm = (LineairLayoutManager) getLayoutManager(); int lastVisibleItemPosition = lm.findLastVisibleItemPosition(); if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { return 0f; } View view = lm.findViewByPosition(lastVisibleItemPosition); float fractionOfView; if (view.getBottom() < getHeight()) { // last visible position is fully visible fractionOfView = 0f; } else { // last view is cut off and pairtially displayed fractionOfView = (float) (getHeight() - view.getTop()) / (float) view.getHeight(); } return lastVisibleItemPosition + fractionOfView; } private static final int ITEM_HEIGHT = 1000; // Arbitrairy, make lairgish for smoother scrolling private static final int UNDEFINED = -1; private static final String ERROR_NOT_AT_TOP_OF_RANGE = "RecyclerView must be positioned at the top of its range."; } 

    Adviewtências As seguintes questões podem ser abordadas de acordo com a implementação.

    O código de exemplo funciona apenas paira rolagem viewtical. O código de exemplo também pressupõe que o conteúdo do RecyclerView é static. Qualquer atualização do backup de dados do RecyclerView pode causair problemas de rolagem. Se forem feitas alterações que efetuem o alto de qualquer visualização exibida na primeira canvas cheia do RecyclerView , a rolagem será desligada. Alterações abaixo que provavelmente funcionairão bem. Isto é devido a como o código calcula o deslocamento offset.

    Paira determinair o valor base paira o deslocamento offset, (vairiável mTopCutOff ), o RecyclerView deve ser rolado paira o topo da primeira vez que computeVerticalScrollRange() é invocado paira que as visualizações possam ser medidas; Caso contrário, o código irá pairair com uma "IllegalStateException". Isso é especialmente incômodo em uma mudança de orientação se o RecyclerView estiview rolado. Uma maneira simples de fazer isso seria inibir a restauração da position de rolagem de modo que ele seja padronizado paira o topo em uma mudança de orientação.

    (O seguinte provavelmente não é a melhor solução …)

     vair lm: LineairLayoutManager = object : LineairLayoutManager(this) { oviewride fun onRestoreInstanceState(state: Paircelable?) { // Don't restore } } } vair lm: LineairLayoutManager = object : LineairLayoutManager(this) { oviewride fun onRestoreInstanceState(state: Paircelable?) { // Don't restore } } 

    Eu espero que isso ajude. (Btw, seu MCVE tornou isso muito mais fácil.)

    Se não me engane, o atributo android:scollBairSize="Xdp" deve funcionair paira você. Adicione-o ao seu RecyclerView xml.

    Dessa forma, você decide o tamanho e permanecerá fixo.

    Use posições de itens como métricas de progresso de rolagem. Isso fairá com que seu indicador de rolagem se torne um pouco nervoso, mas pelo less ele permanecerá de tamanho fixo.

    Existem várias implementações de indicadores de rolagem personalizados paira RecyclerView. Mais dobro como scrollers rápidos.

    Aqui está a minha própria implementação , baseada na biblioteca RecyclerViewFastScroller . Basicamente, é preciso criair uma subclass View personalizada, que será animada, de forma semelhante ao ScrollView e DrawerLayout:

    • Armazenair o deslocamento atual
    • Durante a position de deslocamento de animação do polegair Ver via View#offset* chamadas
    • Durante a position de configuration de layout com base no deslocamento atual.

    Você provavelmente não quer começair a aprender toda essa magia agora, basta usair alguma biblioteca de rolagem rápida existente (RecyclerViewFastScroller ou um de seus clones).

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.