Margin / padding di Anak terakhir di RecyclerView

126

Saya mencoba menambahkan Padding / Margin Bottom di baris terakhir dan Padding / Margin Top di baris pertama. Saya tidak dapat melakukannya di item xml karena akan mempengaruhi semua Childs saya.

Saya memiliki header dan turunan di Adaptor RecyclerView jadi saya tidak bisa menggunakan file

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

Saya perlu menggunakannya secara individual pada baris pertama terakhir dari setiap tajuk

RedEagle
sumber
Gunakan seperti ini: <android.support.v7.widget.RecyclerView android: id = "@ + id / list" android: paddingBottom = "5dp" android: layout_width = "match_parent" android: layout_height = "wrap_content" />
Pankaj Arora
Anda dapat mengubah padding dan margin di onBindViewHolder lalu memanggil setIsRecyclable (false) pada view holder
user3425867

Jawaban:

9

Saya menggunakan ini di 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
sumber
233

Masalah ini bahkan lebih mudah dipecahkan. Anda dapat menerapkan padding yang diperlukan ke RecylerViewdirinya sendiri dan disetel clipToPaddingke false, jika tidak, padding akan memotong area gulir Anda. Berikut ini contohnya

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

Lihat padding akan menambah 4dp di semua sisi termasuk atas dan bawah. Kemudian parameter clipToPadding memastikan item anak Anda tidak dipotong. Sekarang, tambahkan 4dpbantalan ke semua sisi untuk barang anak Anda, dan Anda siap melakukannya. Secara total Anda mendapatkan bantalan 8dp di sisi dan di antara item.

Subin Sebastian
sumber
Ya begitulah biasanya saya melakukannya, tetapi saya RecyclerView saya terdiri dari header dan setiap header memiliki turunannya sendiri, itulah mengapa saya perlu mengaturnya secara terprogram ke baris terakhir dan pertama dari setiap header saja
RedEagle
Tidak yakin saya mengerti. Bagaimana ini terkait dengan header di dalam RecyclerView? Apakah Anda ingin header tidak memiliki padding? Bahkan jika itu masalahnya, Anda dapat menghilangkan padding kiri & kanan menggunakan solusi yang sama.
Subin Sebastian
Saya memiliki header dan setiap header memiliki jumlah non-spesifik anak jadi saya ingin menambahkan padding / margin atas dan anak pertama dan padding / margin bawah pada anak terakhir dari setiap header.
RedEagle
Satu-satunya ide yang saya miliki adalah menetapkan margin atas dan bawah ke dalam tata letak tajuk saya, tetapi saya bertanya-tanya apakah ada cara yang lebih cerdas untuk mencapainya
RedEagle
Jika demikian, Anda cukup menambahkan item palsu ke dalam RecyclerView setelah anak terakhir Anda. Itu adalah cara paling sederhana, jika bukan cara paling cerdas untuk mencapai ini. :)
Subin Sebastian
82

Alih-alih menambahkan padding ke item atas dan bawah, Anda bisa menambahkan padding ke bagian atas dan bawah RecyclerView Anda dan menyetel clipToPaddingatributnya ke 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
sumber
Itu solusi yang mudah, tetapi saya memiliki header dan turunan di RecyclerView saya jadi saya tidak dapat menggunakannya
RedEagle
@RedEagle Coba dan lihat apakah Anda mendapatkan efek yang diinginkan tetapi saya yakin itu berhasil.
Collins Abitekaniza
1
Solusi ini lebih baik dari pada Item Decoration. Ketika saya menggunakan ListAdapter dan mengirimkan daftar yang berbeda, jika item terakhir dari daftar sebelumnya tidak mengubah posisinya tetapi item baru ditambahkan setelahnya, yang pertama akan mempertahankan padding bawahnya meskipun itu bukan item terakhir dalam daftar. lebih.
Ana Koridze
38

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

dan

//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.dll
sumber
1
Hei, sepertinya RecyclerView.ItemDecoration tidak mendapatkan kelas sumber daya lagi, saya baru saja menambahkannya sebagai argumen di konstruktor.
Krtko
2
Solusi Goog! Dengan dukungan tata letak terbalik: gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16
Miha_x64
2
jawaban ini harus diberi suara positif! Meskipun jawaban Subin Sebastian berfungsi dengan baik, namun, dengan ruang ItemDecoration tidak sama.
iroiroys
1
tapi setelah menyisipkan menghapus item itu tidak akan menggambar ulang offset untuk semua item
user924
mungkin benar, karena notifyItemInserted/ Removedakan menarik hanya satu item / menghapus item dan membersihkannya Viewsehingga semua anak lainnya tidak tersentuh. misal, ketika beberapa item pertama ada di daftar (digambar dengan bantalan atas) dan kami menambahkan yang baru ke atas, maka item yang sebelumnya-pertama-sekarang-kedua akan tetap diberi bantalan di atas ... perbaikan mudah adalah memanggil notifyDataSetChanged(paksa menggambar ulang semua ...), yang lebih kompleks membutuhkan beberapa logika untuk mengenali item itu, yang berada di posisi pertama dan / atau terakhir, dipindahkan dan kemudian panggilnotifyItemChanged(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" />

Tambahkan android:clipToPadding="false"dan android:paddingBottom="100dp"di recyclerview Anda.

darshan patel
sumber
2
Hebat! Itu sempurna
KevinB
16

Tambahkan android: clipToPadding = "false" dan android: paddingBottom = "65dp" di recyclerview Anda. Jika Anda menggunakan tombol menu fab dan tindakan pada sel tampilan daur ulang.

<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
sumber
3

Untuk beberapa alasan clipToPadding=falsesolusi lama tidak berhasil untuk saya. Jadi saya menambahkan 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
sumber
1

Saya telah mengubah jawaban @snachmsm jawaban yang luar biasa menjadi lebih baik dan memberi Anda ide bagaimana menggunakan dengan benar

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
sumber