Margem / preenchimento no último filho no RecyclerView


126

Estou tentando adicionar Padding / Margin Bottom na última linha e Padding / Margin Top na primeira linha. Não posso fazer isso no item xml, pois isso afetaria todos os meus filhos.

Tenho cabeçalhos e filhos no meu adaptador RecyclerView, portanto não posso usar o

   android:padding="4dp"
   android:clipToPadding="false"

Eu preciso usá-lo individualmente na última primeira linha de cada cabeçalho


Use assim: <android.support.v7.widget.RecyclerView android: id = "@ + id / list" android: paddingBottom = "5dp" android: layout_width = "match_parent" android: layout_height = "wrap_content" />
— Pankaj Arora

Você poderia mudar o preenchimento e margem em onBindViewHolder e depois chamar setIsRecyclable (false) na visão titular
— user3425867

Respostas:


9

Eu uso isso no kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder(view), position: Int) {
    if (position == itemsList.lastIndex){
        val params = holder.itemView.layoutParams as FrameLayout.LayoutParams
        params.bottomMargin = 100
        holder.itemView.layoutParams = params
    }else{
        val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
        params.bottomMargin = 0
        holder.itemView.layoutParams = params
    }
  //other codes ...
}

232

Esse problema é ainda mais fácil de resolver. Você pode aplicar o preenchimento necessário ao RecylerViewpróprio e definir clipToPaddingcomo false, caso contrário, o preenchimento cortará sua área de rolagem. Aqui está um exemplo

<android.support.v7.widget.RecyclerView
    android:padding="4dp"
    android:clipToPadding="false"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Veja o preenchimento adicionará 4dp em todos os lados, incluindo superior e inferior. Em seguida, o parâmetro clipToPadding garante que os itens filhos não sejam cortados. Agora, adicione 4dpestofamento em todos os lados para os itens do seu filho, e você estará pronto. No total, você obtém um acolchoamento de 8dp nas laterais e entre itens.


Sim isso é como eu costumo fazer isso, mas eu o meu RecyclerView é constituído por cabeçalhos e cada cabeçalho tem seus próprios da criança, é por isso que eu preciso defini-lo por meio de programação para a última e primeira linha de cada somente cabeçalho
— RedEagle

Não tenho certeza se entendi. Como isso está relacionado aos cabeçalhos dentro do RecyclerView? Deseja que os cabeçalhos não tenham preenchimento? Mesmo se for esse o caso, você pode se livrar do preenchimento esquerdo e direito usando a mesma solução.
— Subin Sebastian

Eu tenho cabeçalhos e cada cabeçalho possui uma contagem não específica de filhos, portanto, quero adicionar preenchimento / margem superior e o primeiro filho e preenchimento / margem inferior no último filho de cada cabeçalho.
— RedEagle

A única idéia que tive foi definido superior e margem inferior em layout do meu cabeçalho, mas eu queria saber se existe uma maneira mais inteligente para conseguir isso
— RedEagle

Nesse caso, você pode simplesmente adicionar um item falso ao RecyclerView após o seu último filho. Essa é a maneira mais simples, se não a mais inteligente, de conseguir isso. :)
— Subin Sebastian

82

Em vez de adicionar estofo para a parte superior e itens de fundo, você pode simplesmente adicionar o estofo para a parte superior e inferior do seu RecyclerView e definir o clipToPaddingatributo para false.

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:paddingTop="8dp"
    android:paddingBottom="8dp" />

Essa é a solução mais fácil, mas eu tenho cabeçalhos e criança no meu RecyclerView então eu não posso usá-lo
— RedEagle

@ RedEagle Experimente e veja se você obtém o efeito desejado, mas tenho certeza de que funciona.
— Collins Abitekaniza

1
Esta solução é melhor que a de decoração de itens. Quando estou usando o ListAdapter e enviando uma lista diferente, se o último item da lista anterior não mudou de posição, mas foram adicionados novos itens, o primeiro manterá o preenchimento inferior, mesmo que não seja o último item da lista Mais.
— Ana Koridze 5/09/19

38

use ItemDecoration:

private class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpacesItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast){
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        }
        if(position == 0){
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        }
    }
}

e

//8dp as px
int space = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
            getResources().getDisplayMetrics()); // calculated
//int space = getResources().getDimensionPixelSize(
//    R.dimen.list_item_padding_vertical); // from resources
recyclerView.addItemDecoration(new SpacesItemDecoration(space));

1
Ei, não parece que RecyclerView.ItemDecoration obtenha mais a classe de recurso, apenas a adicionei como argumento no construtor.
— Krtko

2
Solução Goog! Com o apoio disposição invertida: gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16
— Miha_x64

2
esta resposta deve ser votada! Embora a resposta de Subin Sebastian esteja funcionando bem, os espaços com ItemDecoration não são iguais.
— Iroiroys

1
mas depois de inserir a remoção de itens, não redesenhará as compensações para todos os itens
— user924

pode ser verdade, pois notifyItemInserted/ Removedirá desenhar apenas um item / remover item e limpá-lo, Viewdeixando todos os outros filhos intocados. por exemplo, quando algum item é o primeiro da lista (desenhado com preenchimento superior) e estamos adicionando um novo ao topo, o item anteriormente primeiro-segundo-atual ainda será preenchido no topo ... a correção fácil é chamar notifyDataSetChanged(forçar redesenho todos ...), mais complexos precisam de alguma lógica para reconhecer esse item, que estava na primeira e / ou na última posição, movido e depois chamarnotifyItemChanged(newPositionOfOldFirstAndOrLastItem)
— snachmsm

28
<android.support.v7.widget.RecyclerView
    android:id="@+id/rv_tpf"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false"
    android:paddingBottom="100dp" />

Adicione android:clipToPadding="false"e android:paddingBottom="100dp"na sua reciclagem.


2
Impressionante! Isso é perfeito
— KevinB 29/05/19

16

Adicione android: clipToPadding = "false" e android: paddingBottom = "65dp" na sua reciclagem. Se você estiver usando o botão de menu fabuloso e ações na célula de exibição do reciclador.

<androidx.recyclerview.widget.RecyclerView
      android:id="@+id/dinner_recycler_view"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:clipToPadding="false"
      android:paddingBottom="65dp"/>

3

Por alguma razão, a clipToPadding=falsesolução antiga não está funcionando para mim. Então eu adicionei um ItemDecoration

https://gist.github.com/kassim/582888fa5960791264fc92bc41fb6bcf

public class BottomPaddingDecoration extends RecyclerView.ItemDecoration {
    private final int bottomPadding;

    public BottomPaddingDecoration(int bottomPadding) {
        this.bottomPadding = bottomPadding;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
        if (position == parent.getAdapter().getItemCount() - 1) {
            outRect.set(0, 0, 0, bottomPadding);
        }
    }
}

1

Modifiquei a resposta incrível @snachmsm answer para melhor e lhe dou uma ideia de como usar corretamente

public class SpacesItemDecoration extends DividerItemDecoration {
    private int space;

    public SpacesItemDecoration(Context clContext,int oriantation,int space) {
        super(clContext,oriantation);
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect,view,parent,state);
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast){
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        }
       /* if(position == 0){
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        }*/
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.