Margin / padding trong Con cuối cùng trong RecyclerView


126

Tôi đang cố gắng thêm Đệm / Lề dưới ở hàng cuối cùng và Đệm / Lề trên ở hàng đầu tiên. Tôi không thể làm điều đó trong mục xml vì nó sẽ ảnh hưởng đến tất cả các Con của tôi.

Tôi có tiêu đề và con trong Bộ điều hợp RecyclerView nên tôi không thể sử dụng

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

Tôi cần sử dụng nó riêng lẻ trên hàng đầu tiên cuối cùng của mỗi tiêu đề


Sử dụng như thế này: <android.support.v7.widget.RecyclerView android: id = "@ + id / list" android: paddingBottom = "5dp" android: layout_width = "match_parent" android: layout_height = "wrap_content" />
Pankaj Arora,

Bạn có thể thay đổi đệm và lợi nhuận trong onBindViewHolder và sau đó gọi setIsRecyclable (false) trên quan điểm giữ
user3425867

Câu trả lời:


9

Tôi sử dụng cái này trong 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 ...
}

233

Vấn đề này thậm chí còn dễ giải quyết hơn. Bạn có thể áp dụng phần đệm cần thiết cho RecylerViewchính nó và đặt clipToPaddingthành false, nếu không, phần đệm sẽ cắt vùng cuộn của bạn. Đây là một ví dụ

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

Xem phần đệm sẽ thêm 4dp ở tất cả các bên bao gồm cả trên và dưới. Sau đó, tham số clipToPadding đảm bảo các mục con của bạn không bị cắt nhỏ. Bây giờ, thêm phần 4dpđệm vào tất cả các bên cho các món đồ con của bạn, và bạn đã sẵn sàng. Tổng cộng bạn nhận được 8dp đệm ở hai bên và giữa các mục.


Yea đó là cách tôi thường làm điều đó, nhưng tôi RecyclerView của tôi là bao gồm tiêu đề và mỗi tiêu đề có Childs riêng của mình, đó là lý do tại sao tôi cần phải đặt nó lập trình đến dòng cuối cùng và đầu tiên của mỗi tiêu đề duy nhất
RedEagle

Không chắc là tôi hiểu. Điều này có liên quan như thế nào đến các tiêu đề bên trong RecyclerView? Bạn có muốn tiêu đề không có phần đệm không? Ngay cả khi đúng như vậy, bạn có thể loại bỏ phần đệm bên trái và bên phải bằng cách sử dụng cùng một giải pháp.
Subin Sebastian

Tôi có các tiêu đề và mỗi tiêu đề có số lượng phần tử con không cụ thể, vì vậy tôi muốn thêm phần đệm / lề trên cùng và phần đệm con đầu tiên và phần đệm / lề dưới cùng vào phần con cuối cùng của mỗi tiêu đề.
RedEagle

Ý tưởng duy nhất mà tôi đã được thành lập trên và lề dưới vào bố trí phần đầu của tôi, nhưng tôi đã tự hỏi nếu có một cách thông minh hơn để đạt được nó
RedEagle

Trong trường hợp đó, bạn có thể chỉ cần thêm một mục giả mạo vào RecyclerView sau đứa con cuối cùng của bạn. Đó là cách đơn giản nhất, nếu không phải là cách thông minh nhất để đạt được điều này. :)
Subin Sebastian

82

Thay vì thêm phần đệm vào cả mục trên cùng và dưới cùng, Bạn chỉ có thể thêm phần đệm vào đầu và cuối RecyclerView của mình và đặt clipToPaddingthuộc tính thành 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" />

Đó là giải pháp dễ dàng, nhưng tôi có tiêu đề và Childs trong RecyclerView của tôi vì vậy tôi không thể sử dụng nó
RedEagle

@RedEagle Hãy thử và xem liệu bạn có nhận được hiệu quả mong muốn không nhưng tôi chắc chắn rằng nó hoạt động.
Collins Abitekaniza

1
Giải pháp này tốt hơn giải pháp Trang trí Vật phẩm. Khi tôi đang sử dụng ListAdapter và gửi một danh sách khác, nếu mục cuối cùng của danh sách trước đó không thay đổi vị trí của nó nhưng các mục mới được thêm vào sau nó, thì mục trước sẽ giữ phần đệm dưới cùng của nó mặc dù nó không phải là mục cuối cùng trong danh sách. hơn.
Ana Koridze

38

sử dụng 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;
        }
    }
}

//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
Này, có vẻ như RecyclerView.ItemDecoration không lấy được lớp tài nguyên nữa, tôi chỉ thêm nó làm đối số trong hàm tạo.
Krtko

2
Giải pháp Goog! Với sự hỗ trợ bố trí đảo ngược: gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16
Miha_x64

2
câu trả lời này phải được ủng hộ! Mặc dù câu trả lời của Subin Sebastian đang hoạt động tốt, tuy nhiên, với ItemDecoration không gian không bằng nhau.
iroiroys

1
nhưng sau khi chèn loại bỏ các mục, nó sẽ không vẽ lại các phần bù cho tất cả các mục
user924

có thể đúng, vì notifyItemInserted/ Removedsẽ chỉ vẽ một mục / loại bỏ mục và làm sạch nó Viewđể không đụng đến tất cả các mục con khác. Ví dụ: khi một số mục đầu tiên trong danh sách (được vẽ với phần đệm trên cùng) và chúng tôi đang thêm một mục mới vào đầu, thì mục trước đó-hiện tại-thứ hai sẽ vẫn được đệm trên đầu ... cách khắc phục dễ dàng là gọi notifyDataSetChanged(buộc vẽ lại tất cả ...), phức tạp hơn cần một số logic để nhận ra mục đó, ở vị trí đầu tiên và / hoặc cuối cùng, được di chuyển và sau đó gọinotifyItemChanged(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" />

Thêm android:clipToPadding="false"android:paddingBottom="100dp"trong bản tái chế của bạn.


2
Tuyệt vời! Điều đó thật hoàn hảo
KevinB

16

Thêm android: clipToPadding = "false" và android: paddingBottom = "65dp" vào chế độ xem tái chế của bạn. Nếu bạn đang sử dụng nút menu fab và các hành động trên ô xem trình tái chế.

<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

Vì một số lý do, clipToPadding=falsegiải pháp cũ không hoạt động với tôi. Vì vậy, tôi đã thêm một 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

Tôi đã sửa đổi câu trả lời tuyệt vời @snachmsm answer cho tốt hơn và cung cấp cho bạn ý tưởng về cách sử dụng đúng cách

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;
        }*/
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.