Margin / padding ใน Child คนสุดท้ายใน RecyclerView


126

ฉันกำลังพยายามเพิ่ม Padding / Margin Bottom ในแถวสุดท้ายและ Padding / Margin Top ในแถวแรก ฉันไม่สามารถทำได้ในรายการ xml เพราะมันจะส่งผลต่อ Childs ทั้งหมดของฉัน

ฉันมีส่วนหัวและส่วนล่างใน RecyclerView Adapter ของฉันดังนั้นฉันจึงไม่สามารถใช้ไฟล์

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

ฉันต้องใช้ทีละแถวในแถวแรกสุดของแต่ละส่วนหัว


ใช้ดังนี้: <android.support.v7.widget.RecyclerView android: id = "@ + id / list" android: paddingBottom = "5dp" android: layout_width = "match_parent" android: layout_height = "wrap_content" />
Pankaj Arora

คุณสามารถเปลี่ยนช่องว่างภายในและระยะขอบใน onBindViewHolder แล้วเรียก setIsRecyclable (เท็จ) บนตัวยึดมุมมอง
user3425867

คำตอบ:


9

ฉันใช้สิ่งนี้ใน 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

ปัญหานี้จะยิ่งง่ายต่อการแก้ไข คุณสามารถใช้ช่องว่างภายในที่จำเป็นกับRecylerViewตัวมันเองและตั้งค่าclipToPaddingเป็นเท็จมิฉะนั้นช่องว่างภายในจะตัดออกจากพื้นที่เลื่อนของคุณ นี่คือตัวอย่าง

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

ดูช่องว่างภายในจะเพิ่ม 4dp ทุกด้านรวมทั้งด้านบนและด้านล่าง จากนั้นพารามิเตอร์ clipToPadding ทำให้แน่ใจว่ารายการลูกของคุณไม่ได้ถูกตัดออก ตอนนี้เพิ่ม4dpช่องว่างภายในทุกด้านสำหรับรายการเด็กของคุณและคุณก็พร้อมที่จะไป โดยรวมแล้วคุณจะได้รับ 8dp padding ที่ด้านข้างและระหว่างรายการ


ใช่นั่นเป็นวิธีที่ฉันมักจะทำ แต่ฉัน RecyclerView ของฉันประกอบด้วยส่วนหัวและแต่ละส่วนหัวมีลูกของตัวเองนั่นเป็นเหตุผลที่ฉันต้องตั้งค่าโดยใช้โปรแกรมเป็นแถวสุดท้ายและแถวแรกของแต่ละส่วนหัวเท่านั้น
RedEagle

ไม่แน่ใจว่าฉันเข้าใจ สิ่งนี้เกี่ยวข้องกับส่วนหัวภายใน RecyclerView อย่างไร คุณต้องการให้ส่วนหัวไม่มีช่องว่างภายในหรือไม่? แม้ว่าจะเป็นเช่นนั้นคุณสามารถกำจัดช่องว่างด้านซ้ายและด้านขวาได้โดยใช้วิธีแก้ปัญหาเดียวกัน
Subin Sebastian

ฉันมีส่วนหัวและแต่ละส่วนหัวมีจำนวนลูกที่ไม่เฉพาะเจาะจงดังนั้นฉันจึงต้องการเพิ่มช่องว่างด้านบน / ระยะขอบและลูกคนแรกและช่องว่างด้านล่าง / ระยะขอบที่ลูกสุดท้ายของแต่ละส่วนหัว
RedEagle

ความคิดเดียวที่ฉันมีคือกำหนดระยะขอบบนและล่างในเลย์เอาต์ส่วนหัวของฉัน แต่ฉันสงสัยว่ามีวิธีที่ชาญฉลาดกว่าในการบรรลุหรือไม่
RedEagle

ในกรณีนี้คุณสามารถเพิ่มของปลอมลงใน RecyclerView หลังจากลูกคนสุดท้ายของคุณได้ นั่นเป็นวิธีที่ง่ายที่สุดหากไม่ใช่วิธีที่ชาญฉลาดที่สุดในการบรรลุเป้าหมายนี้ :)
Subin Sebastian

82

แทนการเพิ่มช่องว่างภายในทั้งด้านบนและด้านล่างรายการ, คุณก็สามารถเพิ่มช่องว่างภายในไปด้านบนและด้านล่างของ RecyclerView ของคุณและการตั้งค่าแอตทริบิวต์clipToPaddingfalse

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

นั่นเป็นวิธีแก้ปัญหาที่ง่าย แต่ฉันมีส่วนหัวและส่วนย่อยใน RecyclerView ของฉันดังนั้นฉันจึงไม่สามารถใช้งานได้
RedEagle

@RedEagle ลองดูว่าคุณได้รับเอฟเฟกต์ที่ต้องการหรือไม่ แต่ฉันแน่ใจว่าได้ผล
Collins Abitekaniza

1
วิธีนี้ดีกว่าการตกแต่งรายการ เมื่อฉันใช้ ListAdapter และส่งรายการอื่นหากรายการสุดท้ายของรายการก่อนหน้าไม่เปลี่ยนตำแหน่ง แต่มีการเพิ่มรายการใหม่เข้ามารายการเดิมจะคงช่องว่างด้านล่างไว้แม้ว่าจะไม่ใช่รายการสุดท้ายในรายการก็ตาม มากกว่า.
Ana Koridze

38

ใช้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
ดูเหมือนว่า RecyclerViewItemDecoration ไม่ได้รับคลาสทรัพยากรอีกต่อไปฉันเพิ่งเพิ่มเป็นอาร์กิวเมนต์ในตัวสร้าง
Krtko

2
โซลูชัน Goog! ด้วยการสนับสนุนรูปแบบย้อนกลับ: gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16
Miha_x64

2
คำตอบนี้ต้องได้รับการโหวต! แม้ว่าคำตอบของ Subin Sebastian จะทำงานได้ดี แต่ช่องว่าง ItemDecoration นั้นไม่เท่ากัน
iroiroys

1
แต่หลังจากใส่รายการลบแล้วจะไม่วาดใหม่ชดเชยสำหรับรายการทั้งหมด
user924

อาจเป็นจริงเนื่องจากnotifyItemInserted/ Removedจะวาดเพียงรายการเดียว / ลบรายการและทำความสะอาดโดยViewปล่อยให้เด็กคนอื่น ๆ ไม่ถูกแตะต้อง เช่นเมื่อบางรายการเป็นรายการแรกในรายการ (วาดโดยมีช่องว่างด้านบน) และเรากำลังเพิ่มรายการใหม่ไปด้านบนจากนั้นรายการที่หนึ่งในปัจจุบันที่สองก่อนหน้านี้จะยังคงอยู่ด้านบน ... การแก้ไขที่ง่ายคือการเรียกnotifyDataSetChanged(บังคับให้วาดใหม่ ทั้งหมด ... ) ซับซ้อนมากขึ้นต้องการตรรกะบางอย่างในการรับรู้รายการนั้นซึ่งอยู่ในตำแหน่งแรกและ / หรือตำแหน่งสุดท้ายย้ายแล้วโทรnotifyItemChanged(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" />

เพิ่มandroid:clipToPadding="false"และandroid:paddingBottom="100dp"ในมุมมองรีไซเคิลของคุณ


2
! น่ากลัว ที่สมบูรณ์แบบ
KevinB

16

เพิ่ม android: clipToPadding = "false" และ android: paddingBottom = "65dp" ในมุมมองรีไซเคิลของคุณ หากคุณใช้ปุ่มเมนู fab และการดำเนินการกับเซลล์มุมมองรีไซเคิล

<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

ด้วยเหตุผลบางอย่างเก่า clipToPadding=falseวิธีแก้ปัญหาไม่ได้ผลสำหรับฉัน ฉันจึงเพิ่ม 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

ฉันได้แก้ไขคำตอบ @snachmsm คำตอบที่น่าทึ่งให้ดีขึ้นและให้แนวคิดวิธีใช้อย่างถูกต้อง

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;
        }*/
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.