RecyclerView için bir addHeaderView eşdeğeri var mı?


290

Bir recycler görünüm için addHeaderView eşdeğer arıyorum. Temelde 2 düğmeli bir görüntünün liste görünümüne başlık olarak eklenmesini istiyorum. Geri dönüşümcü görünümüne başlık görünümü eklemenin farklı bir yolu var mı? Rehberlik için bir örnek yardımcı olabilir

EDIT 2 (eklenen parça düzenleri):

Günlük ifadeleri ekledikten sonra, getViewType yalnızca 0 konumunu alıyor gibi görünüyor.

10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemCount: 5
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemViewType position: 0
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemViewType position: 0
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> getItemViewType position: 0
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> onCreateViewHolder, viewtype: 0
10-26 16:32:53.766    5449-5449/co.testapp I/logger info Adapter-> onBindViewHolder, viewType: 0

CommentFragment'ı yüklemek için parça geçişi:

@Override
public void onPhotoFeedItemClick(View view, int position) {
    if (fragmentManager == null)
        fragmentManager = getSupportFragmentManager();

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    if (view.getId() == R.id.button_comment){
        CommentFragment commentFragment = CommentFragment.newInstance("","", position);
        fragmentTransaction.add(R.id.main_activity, commentFragment,"comment_fragment_tag");
        fragmentTransaction.addToBackStack(Constants.TAG_COMMENTS);
        fragmentTransaction.commit();
    }
}

Parçanın onCreateView'ı:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_comment, container, false);
    mRecyclerView = (RecyclerView) view.findViewById(R.id.list_recylclerview);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(_context));
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    mAdapter = new CommentAdapter(R.layout.row_list_comments, R.layout.row_header_comments, _context, comments);
    mRecyclerView.setAdapter(mAdapter);
    return view;
}

Geri dönüşüm görünümünü içeren parça:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context="co.testapp.fragments.CommentFragment"
    android:background="@color/white">
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical">
            <android.support.v7.widget.RecyclerView
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/list_recylclerview"
                android:layout_width="match_parent"
                android:layout_height="200dp" />
        </RelativeLayout>
</RelativeLayout>

Yorumlar satır düzeni:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent" android:layout_margin="10dp"
    android:background="@color/white">
    <!--Profile Picture-->
    <ImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:id="@+id/profile_picture"
        android:background="@color/blue_testapp"/>
    <!--Name-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="First Name Last Name"
        android:textSize="16dp"
        android:textColor="@color/blue_testapp"
        android:id="@+id/name_of_poster"
        android:layout_toRightOf="@id/profile_picture"
        />
    <!--Comment-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:layout_marginTop="-5dp"
        android:text="This is a test comment"
        android:textSize="14dp"
        android:textColor="@color/black"
        android:id="@+id/comment"
        android:layout_below="@id/name_of_poster"
        android:layout_toRightOf="@id/profile_picture"/>
</RelativeLayout>

Başlık

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="300dp"
        android:id="@+id/header_photo"
        android:layout_gravity="center_horizontal"/>
</LinearLayout>

Adaptör kodu (beni kullanmaya başladığınız için hister sayesinde):

public class CommentAdapter extends RecyclerView.Adapter<ViewHolder>{

    private final int rowCardLayout;
    public static Context mContext;
    private final int headerLayout;
    private final String [] comments;
    private static final int HEADER = 0;
    private static final int OTHER = 0;

    public CommentAdapter(int rowCardLayout, int headerLayout, Context context, String [] comments) {
        this.rowCardLayout = rowCardLayout;
        this.mContext = context;
        this.comments = comments;
        this.headerLayout = headerLayout;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        logger.i("onCreateViewHolder, viewtype: " + i); //viewtype always returns 0 so OTHER layout is never inflated
        if (i == HEADER) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(headerLayout, viewGroup, false);
            return new ViewHolderHeader(v);
        }
        else if (i == OTHER){
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(rowCardLayout, viewGroup, false);
            return new ViewHolderComments(v);
        }
        else 
          throw new RuntimeException("Could not inflate layout");
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        logger.i("onBindViewHolder, viewType: " + i);

        if (viewHolder instanceof ViewHolderComments)
            ((ViewHolderComments) viewHolder).comment.setText(comments[i].toString());
        if (viewHolder instanceof ViewHolderHeader)
           ((ViewHolderHeader) viewHolder).header.setImageResource(R.drawable.image2);
        else {
            logger.e("no instance of viewholder found");
        }
    }

    @Override
    public int getItemCount() {
        int count = comments.length + 1;
        logger.i("getItemCount: " + count);
        return count;
    }

    @Override
    public int getItemViewType(int position) {
        logger.i("getItemViewType position: " + position);
        if (position == HEADER)
            return HEADER;
        else
            return OTHER;
    }

    public static class ViewHolderComments extends RecyclerView.ViewHolder {
        public TextView comment;
        public ImageView image;

        public ViewHolderComments(View itemView) {
            super(itemView);
            comment = (TextView) itemView.findViewById(R.id.comment);
            image = (ImageView) itemView.findViewById(R.id.image);
        }
    }

    public static class ViewHolderHeader extends RecyclerView.ViewHolder {
        public final ImageView header;

        public ViewHolderHeader(View itemView){
            super(itemView);
            header = (ImageView) itemView.findViewById(R.id.header_photo);
        }
    }
}

Sadece başlık düzeni viewType olarak görüntülenir yukarıdaki kodu kullanarak daima Öyle görünüyor 0'dır bu . Diğer düzeni zorlarsanız benzediğini bu :



Buradaki sorunun bir kopyası olduğu için cevabımı oraya gönderdim :
seb

Yanıtlar:


457

Bunun gibi kolay bir yol yoktur, listview.addHeaderView()ancak başlık için adaptörünüze bir tür ekleyerek bunu başarabilirsiniz.

İşte bir örnek

public class HeaderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;
    String[] data;

    public HeaderAdapter(String[] data) {
        this.data = data;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_ITEM) {
            //inflate your layout and pass it to view holder
            return new VHItem(null);
        } else if (viewType == TYPE_HEADER) {
            //inflate your layout and pass it to view holder
            return new VHHeader(null);
        }

        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof VHItem) {
            String dataItem = getItem(position);
            //cast holder to VHItem and set data
        } else if (holder instanceof VHHeader) {
            //cast holder to VHHeader and set data for header.
        }
    }

    @Override
    public int getItemCount() {
        return data.length + 1;
    }

    @Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position))
            return TYPE_HEADER;

        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {
        return position == 0;
    }

    private String getItem(int position) {
        return data[position - 1];
    }

    class VHItem extends RecyclerView.ViewHolder {
        TextView title;

        public VHItem(View itemView) {
            super(itemView);
        }
    }

    class VHHeader extends RecyclerView.ViewHolder {
        Button button;

        public VHHeader(View itemView) {
            super(itemView);
        }
    }
}

gist bağlantısı -> burada


2
her şey yolunda gibi görünüyor ve işe yarıyor olmalı, ancak geri dönüşümcünün MATCH_PARENT görünümünün bir şey değişip değişmediğini görmesini sağlayın. ayrıca mümkünse, geri dönüştürücünün bu düzenin kökünü görüntülemesini sağlayın (performans için iyi).
EC84B4

1
Bir silah güneşi, geri dönüşüm görünümünü temizleme ve eşleştirme ebeveyn ekleme çalıştı .... Yardımınız için çok teşekkürler! Seni mümkün olan en kısa sürede onaylayacağım.
ViciDroid

14
private String getItem(int position) { return data[position + 1]; }Bir NPE'ye neden olur. Pozisyonumuz birer birer artırıldığından, başlık nedeniyle, verilerimizden doğru öğeyi almak için 1 çıkarmamız gerekir []. private String getItem(int position) { return data[position - 1]; }
Tim Malseed

2
kılavuzunuz sadece basit bir kılavuzsa, LinearLayoutManager kullanın ve öğeye tek bir satırda gösterin. google adı verilen kova satır gördüm google bazı uygulamalarında kullanır.
EC84B4

4
Bu yaklaşımı kullanmak ve ek ekleyebilir @nsL setSpanSizeLookupiçin GridLayoutManagersizin başlık sütunların tümünü alacak, böylece
Dmitry Zaytsev

62

Kolay ve tekrar kullanılabilir ItemDecoration

Statik başlıklar, başka bir değişiklik olmadanItemDecoration ve başka değişiklik olmadan kolayca eklenebilir .

// add the decoration. done.
HeaderDecoration headerDecoration = new HeaderDecoration(/* init */);
recyclerView.addItemDecoration(headerDecoration);

Adaptör veya adaptörün değiştirilmesine gerek olmadığından dekorasyon da yeniden kullanılabilir RecyclerView.

Aşağıda verilen örnek kod, her şey gibi şişirilebilecek bir üst kısma eklenmesini gerektirecektir. Şöyle görünebilir:

Başlık Süsleme örneği

Neden statik ?

Sadece metin ve resim görüntülemeniz gerekiyorsa, bu çözüm tam size göre - düğmeler veya görüntüleme çağrı cihazları gibi kullanıcı etkileşimi olasılığı yoktur, çünkü bu sadece listenizin en üstüne çekilecektir.

Boş liste işleme

Süslemek için bir görünüm yoksa, dekorasyon çizilmez. Yine de boş bir listeyi kendiniz halletmeniz gerekecek. (Olası bir geçici çözüm, adaptöre sahte bir öğe eklemek olacaktır.)

Kod

Dekoratörün başlatılmasına yardımcı olmak için GitHub'da tam kaynak kodunu burada bulabilirsiniz Builderveya sadece aşağıdaki kodu kullanın ve yapıcıya kendi değerlerinizi sağlayın.

Lütfen layout_heightgörünümünüz için doğru ayarladığınızdan emin olun . örneğin match_parentdüzgün çalışmayabilir.

public class HeaderDecoration extends RecyclerView.ItemDecoration {

    private final View mView;
    private final boolean mHorizontal;
    private final float mParallax;
    private final float mShadowSize;
    private final int mColumns;
    private final Paint mShadowPaint;

    public HeaderDecoration(View view, boolean scrollsHorizontally, float parallax, float shadowSize, int columns) {
        mView = view;
        mHorizontal = scrollsHorizontally;
        mParallax = parallax;
        mShadowSize = shadowSize;
        mColumns = columns;

        if (mShadowSize > 0) {
            mShadowPaint = new Paint();
            mShadowPaint.setShader(mHorizontal ?
                    new LinearGradient(mShadowSize, 0, 0, 0,
                            new int[]{Color.argb(55, 0, 0, 0), Color.argb(55, 0, 0, 0), Color.argb(3, 0, 0, 0)},
                            new float[]{0f, .5f, 1f},
                            Shader.TileMode.CLAMP) :
                    new LinearGradient(0, mShadowSize, 0, 0,
                            new int[]{Color.argb(55, 0, 0, 0), Color.argb(55, 0, 0, 0), Color.argb(3, 0, 0, 0)},
                            new float[]{0f, .5f, 1f},
                            Shader.TileMode.CLAMP));
        } else {
            mShadowPaint = null;
        }
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        // layout basically just gets drawn on the reserved space on top of the first view
        mView.layout(parent.getLeft(), 0, parent.getRight(), mView.getMeasuredHeight());

        for (int i = 0; i < parent.getChildCount(); i++) {
            View view = parent.getChildAt(i);
            if (parent.getChildAdapterPosition(view) == 0) {
                c.save();
                if (mHorizontal) {
                    c.clipRect(parent.getLeft(), parent.getTop(), view.getLeft(), parent.getBottom());
                    final int width = mView.getMeasuredWidth();
                    final float left = (view.getLeft() - width) * mParallax;
                    c.translate(left, 0);
                    mView.draw(c);
                    if (mShadowSize > 0) {
                        c.translate(view.getLeft() - left - mShadowSize, 0);
                        c.drawRect(parent.getLeft(), parent.getTop(), mShadowSize, parent.getBottom(), mShadowPaint);
                    }
                } else {
                    c.clipRect(parent.getLeft(), parent.getTop(), parent.getRight(), view.getTop());
                    final int height = mView.getMeasuredHeight();
                    final float top = (view.getTop() - height) * mParallax;
                    c.translate(0, top);
                    mView.draw(c);
                    if (mShadowSize > 0) {
                        c.translate(0, view.getTop() - top - mShadowSize);
                        c.drawRect(parent.getLeft(), parent.getTop(), parent.getRight(), mShadowSize, mShadowPaint);
                    }
                }
                c.restore();
                break;
            }
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (parent.getChildAdapterPosition(view) < mColumns) {
            if (mHorizontal) {
                if (mView.getMeasuredWidth() <= 0) {
                    mView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST),
                            View.MeasureSpec.makeMeasureSpec(parent.getMeasuredHeight(), View.MeasureSpec.AT_MOST));
                }
                outRect.set(mView.getMeasuredWidth(), 0, 0, 0);
            } else {
                if (mView.getMeasuredHeight() <= 0) {
                    mView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST),
                            View.MeasureSpec.makeMeasureSpec(parent.getMeasuredHeight(), View.MeasureSpec.AT_MOST));
                }
                outRect.set(0, mView.getMeasuredHeight(), 0, 0);
            }
        } else {
            outRect.setEmpty();
        }
    }
}

Lütfen dikkat: GitHub projesi benim kişisel oyun alanım. Thorougly hiçbir kütüphane bulunmaktadır, bu yüzden de test edilmez henüz .

Bu ne işe yarıyor?

A ItemDecoration, bir liste öğesinin ek çizimidir. Bu durumda, ilk öğenin üstüne bir dekorasyon çizilir.

Görünüm ölçülür ve düzenlenir, daha sonra ilk öğenin üstüne çizilir. Paralaks efekti eklenirse, doğru sınırlara da kırpılır.


1
zarif bir çözüm görünüyor, ama bir sorum var: ne zaman recyclerView.addItemDecoration çağırmalıyım?
Weibo

1
Teşekkür ederim, iyi çalıştı! Bu yöntemi kullanmanın tek dezavantajı, RecyclerView'de en az 1 satırınızın olması gerektiğidir.
Philip Giuliani

3
Üstbilgi için onClickListener nasıl kullanılır?
Prashant Kedia

1
Aşağıdaki istisnayı alıyorum: java.lang.NullPointerException: Sanal yöntem 'boolean android.support.v7.widget.RecyclerView $ ViewHolder.shouldIgnore ()' null bir nesne başvurusu çağrılmaya çalışılıyor
Makalele

1
Dekorasyondaki manzaraya erişmenin herhangi bir yolu var mı? Metni dinamik olarak ayarlamak istiyorum.
SMahdiS

44

Burada bulunan kütüphanemi kullanmaktan çekinmeyin .

Bu başlık oluşturmak yapalım Viewherhangi için RecyclerViewkullandığı o LinearLayoutManagerveya GridLayoutManagersadece basit bir yöntem çağrısı ile.

resim açıklamasını buraya girin


üstbilgi yüksekliği nasıl değiştirilir?
ingsaurabh

Altta üstbilgi göstermek için bunu kullandım ya da altbilgi olarak söyleyebilirim, ancak görünümüm ilk kez yüklendiğinde son konumu ve tüm liste öğelerini ters sırada gösteren bir sorun alıyorum. @blipinsk
Ronak Joshi


Lipinski bu kütüphaneyi emekli oldu ve yerine bunu kullanarak önerir: github.com/Karumi/HeaderRecyclerView
Radley'ye

1
Ben ediyorum emekli tam olarak bu kütüphaneyi. Hala bunun için hafif bir destek sağlıyorum, ama gerçekten bunun yerine özel adaptörle gitmeyi öneriyorum (örneğin Karumi'den).
Bartek Lipinski

31

Bir Recycler görünümünde öğelerle başlık oluşturmanızı gösterecek.Başlıklı geri dönüşümcü görünümü

Adım 1- Gradle dosyanıza bağımlılık ekleyin.

compile 'com.android.support:recyclerview-v7:23.2.0'
// CardView
compile 'com.android.support:cardview-v7:23.2.0'

Cardview dekorasyon amaçlı kullanılır.

Adım 2- Üç xml dosyası oluşturun. Ana faaliyet için bir tane. Başlık düzeni için ikinci. Liste öğesi düzeni için üçüncü.

activity_main.xml

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/my_recycler_view"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

header.xml

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="2dp">

    <TextView
        android:id="@+id/txtHeader"
        android:gravity="center"
        android:textColor="#000000"
        android:textSize="@dimen/abc_text_size_large_material"
        android:background="#DCDCDC"
        android:layout_width="match_parent"
        android:layout_height="50dp" />

</android.support.v7.widget.CardView>

list.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardElevation="1dp">

        <TextView
            android:id="@+id/txtName"
            android:text="abc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.v7.widget.CardView>

</LinearLayout>

Adım 3- Üç fasulye sınıfı oluşturun.

Header.java

public class Header extends ListItem {
    private String header;

    public String getHeader() {
        return header;
    }
    public void setHeader(String header) {
        this.header = header;
    }
}

ContentItem.java

public class ContentItem extends ListItem {

    private String name;
    private String rollnumber;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    public String getRollnumber() {
        return rollnumber;
    }

    public void setRollnumber(String rollnumber) {
        this.rollnumber = rollnumber;
    }
}

ListItem.java

public class ListItem {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Adım 4- MyRecyclerAdapter.java adlı bir bağdaştırıcı oluşturun

public class MyRecyclerAdapter extends  RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;

    //Header header;
    List<ListItem> list;
    public MyRecyclerAdapter(List<ListItem> headerItems) {
        this.list = headerItems;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        if (viewType == TYPE_HEADER) {
            View v = inflater.inflate(R.layout.header, parent, false);
            return  new VHHeader(v);
        } else {
            View v = inflater.inflate(R.layout.list, parent, false);
            return new VHItem(v);
        }
        throw new IllegalArgumentException();
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof VHHeader) {
           // VHHeader VHheader = (VHHeader)holder;
            Header  currentItem = (Header) list.get(position);
            VHHeader VHheader = (VHHeader)holder;
            VHheader.txtTitle.setText(currentItem.getHeader());
        } else if (holder instanceof VHItem) 
            ContentItem currentItem = (ContentItem) list.get(position);
            VHItem VHitem = (VHItem)holder;
            VHitem.txtName.setText(currentItem.getName());
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position))
            return TYPE_HEADER;
        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {
        return list.get(position) instanceof Header;
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class VHHeader extends RecyclerView.ViewHolder{
        TextView txtTitle;
        public VHHeader(View itemView) {
            super(itemView);
            this.txtTitle = (TextView) itemView.findViewById(R.id.txtHeader);
        }
    }
    class VHItem extends RecyclerView.ViewHolder{
        TextView txtName;
        public VHItem(View itemView) {
            super(itemView);
            this.txtName = (TextView) itemView.findViewById(R.id.txtName);
        }
    }
}

Adım 5- MainActivity'de aşağıdaki kodu ekleyin:

public class MainActivity extends AppCompatActivity {
    RecyclerView recyclerView;
    List<List<ListItem>> arraylist;
    MyRecyclerAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        adapter = new MyRecyclerAdapter(getList());
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
    }

    private ArrayList<ListItem> getList() {
        ArrayList<ListItem> arrayList = new ArrayList<>();
        for(int j = 0; j <= 4; j++) {
            Header header = new Header();
            header.setHeader("header"+j);
            arrayList.add(header);
            for (int i = 0; i <= 3; i++) {
                ContentItem item = new ContentItem();
                item.setRollnumber(i + "");
                item.setName("A" + i);
                arrayList.add(item);
            }
        }
        return arrayList;
    }

}

GetList () işlevi, üstbilgiler ve liste öğeleri için verileri dinamik olarak oluşturur.


En iyi cevaplardan biri. Navigasyon menüsünde kullandım Navigasyon menüsü
Saurabh Bhandari

Bu iyi bir basit cevap - 2 veri öğesini kolayca tek bir ListItem'de birleştirmek için bir hile düşünemedim - miras kolay ve ulaşılabilir hale getirdi - duh!
yura

8

SectionedRecyclerViewAdapter kütüphanesini kullanarak bunu başarabilirsiniz , bu bölümün bir Başlık, Altbilgi ve İçerik (öğe listesi) olduğu "Bölümler" kavramı vardır. Sizin durumunuzda yalnızca bir Bölüme ihtiyacınız olabilir, ancak bir çok bölümünüz olabilir:

resim açıklamasını buraya girin

1) Özel Bölüm sınıfı oluşturun:

class MySection extends StatelessSection {

    List<String> myList = Arrays.asList(new String[] {"Item1", "Item2", "Item3" });

    public MySection() {
        // call constructor with layout resources for this Section header, footer and items 
        super(R.layout.section_header, R.layout.section_footer,  R.layout.section_item);
    }

    @Override
    public int getContentItemsTotal() {
        return myList.size(); // number of items of this section
    }

    @Override
    public RecyclerView.ViewHolder getItemViewHolder(View view) {
        // return a custom instance of ViewHolder for the items of this section
        return new MyItemViewHolder(view);
    }

    @Override
    public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
        MyItemViewHolder itemHolder = (MyItemViewHolder) holder;

        // bind your view here
        itemHolder.tvItem.setText(myList.get(position));
    }
}

2) Öğeler için özel bir ViewHolder oluşturun:

class MyItemViewHolder extends RecyclerView.ViewHolder {

    private final TextView tvItem;

    public MyItemViewHolder(View itemView) {
        super(itemView);

        tvItem = (TextView) itemView.findViewById(R.id.tvItem);
    }
}

3) ReclyclerView cihazınızı SectionedRecyclerViewAdapter ile kurun

// Create an instance of SectionedRecyclerViewAdapter 
SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();

MySection mySection = new MySection();

// Add your Sections
sectionAdapter.addSection(mySection);

// Set up your RecyclerView with the SectionedRecyclerViewAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(sectionAdapter);

bu kullanımı kolay ama yatay kaydırma için nasıl kullanılır .. yönünü yatay olarak değiştirdiğimde tüm recyclerview yatay kaydırmaya değişir, ancak öğe parçasının sadece yatay kaydırma olmasını istiyorum .. lütfen bana yardım et
roshan posakya

6

Üstbilginizi ve RecyclerView öğenizi bir NestedScrollView öğesine yerleştirebilirsiniz:

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <include
            layout="@layout/your_header"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list_recylclerview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

Kaydırmanın düzgün çalışması için RecyclerView cihazınızda iç içe kaydırmayı devre dışı bırakmanız gerekir:

myRecyclerView.setNestedScrollingEnabled(false);

3
nestedScrollingEnabled = "false": veya kullanım android
radley

android: nestedScrollingEnabled = "false", berbat bir api seviyesi 21 gerektirir. Neyse harika bir çözüm! Aynı başka bir altbilgi veya belki de ikinci geri dönüşüm görünümü eklemeniz gerekir?
Makalele

47
ASLA bunu yapmayın. Bu iyi çalışıyor gibi görünecek. Ama aslında yaptığı şey, kaydı srollView'a geçirmesidir. Yani recyclerView kendi başına bir şey yapmaz. Görünüm geri dönüşümü yok. RecyclerView'ınızda çok fazla öğe alırsanız uygulama çökecektir, çünkü şimdi basit bir scrollView gibi davranıyor.
VipulKumar

2
@ VipulKumar'ın yorumu tamamen doğru. Başka bir kaydırma görünümünde recyclerview kullandığınızda geri dönüşüm olmaz ve tüm öğeler oluşturulur.
VolkanSahin45

recyclerView öğeleriniz 10'dan küçükse bunu yapabilirsiniz.
😄

5

Yerel API böyle bir "addHeader" özelliğine sahip değildir, ancak "addItem" kavramına sahiptir.

FlexibleAdapter projemde de üstbilgilerin bu özel özelliğini ve altbilgiler için genişletmeyi ekleyebildim . Buna Kaydırılabilir Üstbilgi ve Altbilgi adını verdim .

İşte nasıl çalışıyorlar:

Kaydırılabilir Üstbilgiler ve Altbilgiler, diğerleriyle birlikte kaydırılan özel öğelerdir, ancak ana öğelere (iş öğeleri) ait değildir ve her zaman ana öğelerin yanındaki bağdaştırıcı tarafından kullanılırlar. Bu eşyalar kalıcı olarak ilk ve son konumlarda bulunur.

resim açıklamasını buraya girin

Onlar hakkında söylenecek çok şey var, ayrıntılı wiki sayfasını okumak daha iyi .

FlexibleAdapter ayrıca üstbilgiler / bölümler oluşturmanıza izin verir, ayrıca onları yapışkan ve onlarca diğer genişletilebilir öğeler, sonsuz kaydırma, UI uzantıları vb gibi özellikleri tek bir kütüphanede olabilir!


4

Bu gönderiye dayanarak yazıyı , RecyclerView.Adapter öğesinin gelişigüzel sayıda üstbilgi ve altbilgiyi destekleyen bir alt sınıfı oluşturdum.

https://gist.github.com/mheras/0908873267def75dc746

Bir çözüm gibi görünse de, bu şeyin LayoutManager tarafından yönetilmesi gerektiğini düşünüyorum. Ne yazık ki, şimdi buna ihtiyacım var ve sıfırdan bir StaggeredGridLayoutManager uygulamak için zamanım yok (hatta daha da uzatmak).

Hala test ediyorum, ancak isterseniz deneyebilirsiniz. Bununla ilgili herhangi bir sorun bulursanız lütfen bize bildirin.


2

Yukarıdaki tüm kullanım durumlarını kapsayan bir çözüm daha vardır: CompoundAdapter: https://github.com/negusoft/CompoundAdapter-android

Üstbilgiyi temsil eden tek bir öğeye sahip bir bağdaştırıcıyla birlikte Bağdaştırıcınızı olduğu gibi tutan bir Bağdaştırıcı Grubu oluşturabilirsiniz. Kod kolay ve okunabilir:

AdapterGroup adapterGroup = new AdapterGroup();
adapterGroup.addAdapter(SingleAdapter.create(R.layout.header));
adapterGroup.addAdapter(new CommentAdapter(...));

recyclerView.setAdapter(adapterGroup);

BağdaştırıcıGrubu da yuvalanmaya izin verir, bu nedenle bölümlü bir bağdaştırıcı için bölüm başına bir Bağdaştırıcı Grubu oluşturabilirsiniz. Ardından tüm bölümleri bir kök AdapterGroup'a koyun.


1

HeaderView, LayoutManager'a bağlıdır. Varsayılan LayoutManagers'ın hiçbiri bunu desteklemez ve muhtemelen alışmaz. ListView'daki HeaderView, önemli bir yarar olmadan çok fazla karmaşıklık yaratır.

Sağlanırsa, Başlıklar için öğeler ekleyen bir temel bağdaştırıcı sınıfı oluşturmanızı öneririm. Başlığın var olup olmamasına bağlı olarak bunları düzgün bir şekilde dengelemek için bildirim * yöntemlerini geçersiz kılmayı unutmayın.


Baz adaptörlü bir geri dönüşüm görünümü kullanan beni işaret edebileceğiniz bir örnek var mı? Teşekkürler!
ViciDroid

Listede Üstbilgi / Altbilgi için gerçekten önemli bir avantaj var: görünümü dışına kaydırabilirsiniz. Görünür sıraların miktarının, pinguinler çıkar çıkmaz neredeyse iki katına çıktığı bu örneği görün , bunu yapmanın başka bir yolunun farkında değilim, ListView.addHeaderViewya da bu sorunun cevabı.
TWiStErRob

Doğru anladığımı sanmıyorum. Adaptördeki ilk öğe ise, neden örnekteki gibi kaydırılamıyor?
yigit

2
Nihai olarak işaretlendikleri için bildirim * yöntemlerini geçersiz kılamazsınız.
mato

hmm özür dilerim kontrol etmedi. Bunun yerine, sarılmış bağdaştırıcıya gözlenebilir bir ekleyen ve kaydırılan olayları kendinden gönderen bir bağdaştırıcı sarıcı oluşturabilirsiniz.
yigit

1
First - extends RecyclerView.Adapter<RecyclerView.ViewHolder>

public class MenuAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

Sonra - getItemViewTpe *** yöntemini geçersiz kıl Daha Fazla Önemli

@Override
public int getItemViewType(int position) {
    return position;
}

yöntemi onCreateViewHolder

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.menu_item, parent, false);
    View header = LayoutInflater.from(parent.getContext()).inflate(R.layout.menu_header_item, parent, false);
    Log.d("onCreateViewHolder", String.valueOf(viewType));

    if (viewType == 0) {
        return new MenuLeftHeaderViewHolder(header, onClickListener);
    } else {
        return new MenuLeftViewHolder(view, onClickListener);
    }
}

BindViewHolder yöntemi

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (position == 0) {
        MenuHeaderViewHolder menuHeaderViewHolder = (MenuHeaderViewHolder) holder;
        menuHeaderViewHolder.mTitle.setText(sMenuTitles[position]);
        menuHeaderViewHolder.mImage.setImageResource(sMenuImages[position]);
    } else {
        MenuViewHolder menuLeftViewHolder = (MenuLeftViewHolder) holder;
        menuViewHolder.mTitle.setText(sMenuTitles[position]);
        menuViewHolder.mImage.setImageResource(sMenuImages[position]);
    }
}

sonunda ViewHolders sınıfını statik olarak uygular

public static class MenuViewHolder extends RecyclerView.ViewHolder 

public static class MenuLeftHeaderViewHolder extends RecyclerView.ViewHolder 

1

burada geri dönüşüm görünümü için bazı itemdecoration

public class HeaderItemDecoration extends RecyclerView.ItemDecoration {

private View customView;

public HeaderItemDecoration(View view) {
    this.customView = view;
}

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    super.onDraw(c, parent, state);
    customView.layout(parent.getLeft(), 0, parent.getRight(), customView.getMeasuredHeight());
    for (int i = 0; i < parent.getChildCount(); i++) {
        View view = parent.getChildAt(i);
        if (parent.getChildAdapterPosition(view) == 0) {
            c.save();
            final int height = customView.getMeasuredHeight();
            final int top = view.getTop() - height;
            c.translate(0, top);
            customView.draw(c);
            c.restore();
            break;
        }
    }
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    if (parent.getChildAdapterPosition(view) == 0) {
        customView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST),
                View.MeasureSpec.makeMeasureSpec(parent.getMeasuredHeight(), View.MeasureSpec.AT_MOST));
        outRect.set(0, customView.getMeasuredHeight(), 0, 0);
    } else {
        outRect.setEmpty();
    }
}
}      

1

@ Hister’e dayalı bir uygulama yaptımKişisel amaçlar için ama kalıtım kullanarak.

Ben (eklemedeki 1 gibi uygulama detayları mekanizmalarını gizlemek itemCount, 1 çıkarma positionsoyut bir süper sınıfında) HeadingableRecycleAdapterBağdaştırıcısından gibi gerekli yöntemleri uygulayarak, onBindViewHolder, getItemViewTypeve getItemCountyöntemler nihai ve müşteriye gizli mantığı ile yeni yöntemler sağlayarak bu hale:

  • onAddViewHolder(RecyclerView.ViewHolder holder, int position),
  • onCreateViewHolder(ViewGroup parent),
  • itemCount()

İşte HeadingableRecycleAdaptersınıf ve bir müşteri. Üstbilgi düzenini biraz sabit kodlu bıraktım çünkü ihtiyaçlarıma uyuyor.

public abstract class HeadingableRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int HEADER_VIEW_TYPE = 0;

    @LayoutRes
    private int headerLayoutResource;
    private String headerTitle;
    private Context context;

    public HeadingableRecycleAdapter(@LayoutRes int headerLayoutResourceId, String headerTitle, Context context) {
        this.headerLayoutResource = headerLayoutResourceId;
        this.headerTitle = headerTitle;
        this.context = context;
    }

    public Context context() {
        return context;
    }

    @Override
    public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == HEADER_VIEW_TYPE) {
            return new HeaderViewHolder(LayoutInflater.from(context).inflate(headerLayoutResource, parent, false));
        }
        return onCreateViewHolder(parent);
    }

    @Override
    public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int viewType = getItemViewType(position);
        if (viewType == HEADER_VIEW_TYPE) {
            HeaderViewHolder vh = (HeaderViewHolder) holder;
            vh.bind(headerTitle);
        } else {
            onAddViewHolder(holder, position - 1);
        }
    }

    @Override
    public final int getItemViewType(int position) {
        return position == 0 ? 0 : 1;
    }

    @Override
    public final int getItemCount() {
        return itemCount() + 1;
    }

    public abstract int itemCount();

    public abstract RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);

    public abstract void onAddViewHolder(RecyclerView.ViewHolder holder, int position);

}



@PerActivity
public class IngredientsAdapter extends HeadingableRecycleAdapter {
    public static final String TITLE = "Ingredients";
    private List<Ingredient> itemList;


    @Inject
    public IngredientsAdapter(Context context) {
        super(R.layout.layout_generic_recyclerview_cardified_header, TITLE, context);
    }

    public void setItemList(List<Ingredient> itemList) {
        this.itemList = itemList;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
        return new ViewHolder(LayoutInflater.from(context()).inflate(R.layout.item_ingredient, parent, false));
    }

    @Override
    public void onAddViewHolder(RecyclerView.ViewHolder holder, int position) {
        ViewHolder vh = (ViewHolder) holder;
        vh.bind(itemList.get(position));
    }

    @Override
    public int itemCount() {
        return itemList == null ? 0 : itemList.size();
    }

    private String getQuantityFormated(double quantity, String measure) {
        if (quantity == (long) quantity) {
            return String.format(Locale.US, "%s %s", String.valueOf(quantity), measure);
        } else {
            return String.format(Locale.US, "%.1f %s", quantity, measure);
        }
    }


    class ViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.text_ingredient)
        TextView txtIngredient;

        ViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        void bind(Ingredient ingredient) {
            String ingredientText = ingredient.getIngredient();
            txtIngredient.setText(String.format(Locale.US, "%s %s ", getQuantityFormated(ingredient.getQuantity(),
                    ingredient.getMeasure()), Character.toUpperCase(ingredientText.charAt(0)) +
                    ingredientText
                            .substring(1)));
        }
    }
}

1

Belki üstbilgi ve geri dönüşüm görünümünü bir coordinatorlayout :

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:elevation="0dp">

    <View
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_scrollFlags="scroll" />

</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />


Buradaki sorun, liste ekrandan daha kısa olsa bile, her zaman AppBarLayout'un yüksekliğinin kaydırılmasına izin vermesidir. Burada
Daniel López Lacalle

0

Muhtemelen http://alexzh.com/tutorials/multiple-row-layouts-using-recyclerview/ yardımcı olacaktır. Yalnızca RecyclerView ve CardView kullanır. İşte bir adaptör:

public class DifferentRowAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<CityEvent> mList;
    public DifferentRowAdapter(List<CityEvent> list) {
        this.mList = list;
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        switch (viewType) {
            case CITY_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_city, parent, false);
                return new CityViewHolder(view);
            case EVENT_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_event, parent, false);
                return new EventViewHolder(view);
        }
        return null;
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        CityEvent object = mList.get(position);
        if (object != null) {
            switch (object.getType()) {
                case CITY_TYPE:
                    ((CityViewHolder) holder).mTitle.setText(object.getName());
                    break;
                case EVENT_TYPE:
                    ((EventViewHolder) holder).mTitle.setText(object.getName());
                    ((EventViewHolder) holder).mDescription.setText(object.getDescription());
                    break;
            }
        }
    }
    @Override
    public int getItemCount() {
        if (mList == null)
            return 0;
        return mList.size();
    }
    @Override
    public int getItemViewType(int position) {
        if (mList != null) {
            CityEvent object = mList.get(position);
            if (object != null) {
                return object.getType();
            }
        }
        return 0;
    }
    public static class CityViewHolder extends RecyclerView.ViewHolder {
        private TextView mTitle;
        public CityViewHolder(View itemView) {
            super(itemView);
            mTitle = (TextView) itemView.findViewById(R.id.titleTextView);
        }
    }
    public static class EventViewHolder extends RecyclerView.ViewHolder {
        private TextView mTitle;
        private TextView mDescription;
        public EventViewHolder(View itemView) {
            super(itemView);
            mTitle = (TextView) itemView.findViewById(R.id.titleTextView);
            mDescription = (TextView) itemView.findViewById(R.id.descriptionTextView);
        }
    }
}

Ve işte bir varlık:

public class CityEvent {
    public static final int CITY_TYPE = 0;
    public static final int EVENT_TYPE = 1;
    private String mName;
    private String mDescription;
    private int mType;
    public CityEvent(String name, String description, int type) {
        this.mName = name;
        this.mDescription = description;
        this.mType = type;
    }
    public String getName() {
        return mName;
    }
    public void setName(String name) {
        this.mName = name;
    }
    public String getDescription() {
        return mDescription;
    }
    public void setDescription(String description) {
        this.mDescription = description;
    }
    public int getType() {
        return mType;
    }
    public void setType(int type) {
        this.mType = type;
    }
}

0

addHeaderView oluşturabilir ve kullanabilirsiniz

adapter.addHeaderView(View).

Bu kod addHeaderViewbirden fazla üstbilgi için derleme yapar . başlıklar:

android:layout_height="wrap_content"

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int TYPE_ITEM = -1;
    public class MyViewSHolder extends RecyclerView.ViewHolder {
        public MyViewSHolder (View view) {
            super(view);
        }
        // put you code. for example:
        View mView;
        ...
    }

    public class ViewHeader extends RecyclerView.ViewHolder {
        public ViewHeader(View view) {
            super(view);
        }
    }

    private List<View> mHeaderViews = new ArrayList<>();
    public void addHeaderView(View headerView) {
        mHeaderViews.add(headerView);
    }

    @Override
    public int getItemCount() {
       return ... + mHeaderViews.size();
    }

    @Override
    public int getItemViewType(int position) {
        if (mHeaderViews.size() > position) {
            return position;
        }

        return TYPE_ITEM;
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType != TYPE_ITEM) {
            //inflate your layout and pass it to view holder
            return new ViewHeader(mHeaderViews.get(viewType));
        }
        ...
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int basePosition1) {
        if (holder instanceof ViewHeader) {
            return;
        }
        int basePosition = basePosition1 -  mHeaderViews.size();
        ...
    }
}

0

Birkaç yıl oldu, ancak daha sonra herhangi birinin bunu okuması durumunda ...

Yukarıdaki kod kullanıldığında, viewType her zaman 0 olduğu için yalnızca başlık düzeni görüntülenir.

Sorun sürekli beyandadır:

private static final int HEADER = 0;
private static final int OTHER = 0;  <== bug 

Her ikisini de sıfır olarak bildirirseniz, daima sıfır alırsınız!


0

EC84B4 cevabı tarafından önerilen aynı yaklaşımı uyguladım , ancak RecycleViewAdapter'ı soyutladım ve arayüzler aracılığıyla kolayca yeniden boyutlandırılabilir hale getirdim.

Bu yüzden yaklaşımımı kullanmak için projenize aşağıdaki temel sınıfları ve arayüzleri eklemelisiniz:

1) Adaptör (genel tip T toplanması ve ek tip (gerekirse) genel tip P parametresi için veri sağlayan arayüz)

public interface IRecycleViewListHolder<T,P>{
            P getAdapterParameters();
            T getItem(int position);
            int getSize();
    }

2) fabrika öğeleri bağlamak için (başlık / öğe):

public interface IViewHolderBinderFactory<T,P> {
        void bindView(RecyclerView.ViewHolder holder, int position,IRecycleViewListHolder<T,P> dataHolder);
}

3) viewHolders için fabrika (başlık / ürün):

public interface IViewHolderFactory {
    RecyclerView.ViewHolder provideInflatedViewHolder(int viewType, LayoutInflater layoutInflater,@NonNull ViewGroup parent);
}

4) Başlıklı Adaptör için temel sınıf:

public class RecycleViewHeaderBased<T,P> extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    public final static int HEADER_TYPE = 1;
    public final static int ITEM_TYPE = 0;
    private final IRecycleViewListHolder<T, P> dataHolder;
    private final IViewHolderBinderFactory<T,P> binderFactory;
    private final IViewHolderFactory viewHolderFactory;

    public RecycleViewHeaderBased(IRecycleViewListHolder<T,P> dataHolder, IViewHolderBinderFactory<T,P> binderFactory, IViewHolderFactory viewHolderFactory) {
        this.dataHolder = dataHolder;
        this.binderFactory = binderFactory;
        this.viewHolderFactory = viewHolderFactory;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        return viewHolderFactory.provideInflatedViewHolder(viewType,layoutInflater,parent);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            binderFactory.bindView(holder, position,dataHolder);
    }

    @Override
    public int getItemViewType(int position) {
        if(position == 0)
            return HEADER_TYPE;
        return ITEM_TYPE;
    }

    @Override
    public int getItemCount() {
        return dataHolder.getSize()+1;
    }
}

Kullanım örneği :

1) IRecycleViewListHolder uygulaması:

public class AssetTaskListData implements IRecycleViewListHolder<Map.Entry<Integer, Integer>, GroupedRecord> {
    private List<Map.Entry<Integer, Integer>> assetCountList;
    private GroupedRecord record;

    public AssetTaskListData(Map<Integer, Integer> assetCountListSrc, GroupedRecord record) {
        this.assetCountList =  new ArrayList<>();
        for(Object  entry: assetCountListSrc.entrySet().toArray()){
            Map.Entry<Integer,Integer> entryTyped = (Map.Entry<Integer,Integer>)entry;
            assetCountList.add(entryTyped);
        }
        this.record = record;
    }

    @Override
    public GroupedRecord getAdapterParameters() {
        return record;
    }

    @Override
    public Map.Entry<Integer, Integer> getItem(int position) {
        return assetCountList.get(position-1);
    }

    @Override
    public int getSize() {
        return assetCountList.size();
    }
}

2) IViewHolderBinderFabrika uygulaması:

public class AssetTaskListBinderFactory implements IViewHolderBinderFactory<Map.Entry<Integer, Integer>, GroupedRecord> {
    @Override
    public void bindView(RecyclerView.ViewHolder holder, int position, IRecycleViewListHolder<Map.Entry<Integer, Integer>, GroupedRecord> dataHolder) {
        if (holder instanceof AssetItemViewHolder) {
            Integer assetId = dataHolder.getItem(position).getKey();
            Integer assetCount = dataHolder.getItem(position).getValue();
            ((AssetItemViewHolder) holder).bindItem(dataHolder.getAdapterParameters().getRecordId(), assetId, assetCount);
        } else {
            ((AssetHeaderViewHolder) holder).bindItem(dataHolder.getAdapterParameters());
        }
    }
}

3) IViewHolderFactory uygulaması:

public class AssetTaskListViewHolderFactory implements IViewHolderFactory {
    private IPropertyTypeIconMapper iconMapper;
    private ITypeCaster caster;

    public AssetTaskListViewHolderFactory(IPropertyTypeIconMapper iconMapper, ITypeCaster caster) {
        this.iconMapper = iconMapper;
        this.caster = caster;
    }

    @Override
    public RecyclerView.ViewHolder provideInflatedViewHolder(int viewType, LayoutInflater layoutInflater, @NonNull ViewGroup parent) {
        if (viewType == RecycleViewHeaderBased.HEADER_TYPE) {
            AssetBasedHeaderItemBinding item = DataBindingUtil.inflate(layoutInflater, R.layout.asset_based_header_item, parent, false);
            return new AssetHeaderViewHolder(item.getRoot(), item, caster);
        }
        AssetBasedListItemBinding item = DataBindingUtil.inflate(layoutInflater, R.layout.asset_based_list_item, parent, false);
        return new AssetItemViewHolder(item.getRoot(), item, iconMapper, parent.getContext());
    }
}

4) Türetme adaptörü

public class AssetHeaderTaskListAdapter extends RecycleViewHeaderBased<Map.Entry<Integer, Integer>, GroupedRecord> {
   public AssetHeaderTaskListAdapter(IRecycleViewListHolder<Map.Entry<Integer, Integer>, GroupedRecord> dataHolder,
                                      IViewHolderBinderFactory binderFactory,
                                      IViewHolderFactory viewHolderFactory) {
        super(dataHolder, binderFactory, viewHolderFactory);
    }
}

5) Örnek adaptör sınıfı:

private void setUpAdapter() {
        Map<Integer, Integer> objectTypesCountForGroupedTask = groupedTaskRepository.getObjectTypesCountForGroupedTask(this.groupedRecordId);
        AssetTaskListData assetTaskListData = new AssetTaskListData(objectTypesCountForGroupedTask, getGroupedRecord());
        adapter = new AssetHeaderTaskListAdapter(assetTaskListData,new AssetTaskListBinderFactory(),new AssetTaskListViewHolderFactory(iconMapper,caster));
        assetTaskListRecycler.setAdapter(adapter);
    }

PS : AssetItemViewHolder, AssetBasedListItemBinding, vb benim uygulama kendi amaçları için kendi tarafından takas gereken kendi yapıları kendi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.