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

RedEagle
fonte
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 ...
}
Radesh
fonte
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.

Subin Sebastian
fonte
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" />
Collins Abitekaniza
fonte
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));
snachmsm
fonte
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.

darshan patel
fonte
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"/>
Yogesh Shinde
fonte
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);
        }
    }
}
kassim
fonte
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;
        }*/
    }
}
sourav pandit
fonte