Daftar yang dapat diperluas dengan RecyclerView?

95

Mungkinkah menggunakan item daftar yang dapat diperluas dengan RecyclerView baru? Suka ExpandableListView?

Dariusz Rusin
sumber
1
Anda dapat melihat jam android di sumber google pada android 6.0
zys
@zys Di mana saya dapat menemukan kode sumber contoh jam android ini?
AppiDevo
1
Anda dapat menggunakan viewType yang berbeda untuk memuat tata letak yang berbeda, saat Anda mengklik tombol perluas. Solusi ini digunakan oleh Android Clock: android.googlesource.com/platform/packages/apps/DeskClock
zys
lihat jawaban sederhana saya stackoverflow.com/a/48092441/5962715
Kiran Benny Joseph

Jawaban:

121

Ini mudah dilakukan dengan LayoutManagers stok, semuanya tergantung pada bagaimana Anda mengelola adaptor Anda.

Saat Anda ingin memperluas bagian, Anda cukup menambahkan item baru ke adaptor Anda setelah header. Ingatlah untuk memanggil notifyItemRangeInserted saat Anda melakukan ini. Untuk menciutkan bagian Anda cukup menghapus item yang relevan, dan memanggil notifyItemRangeRemoved (). Untuk setiap perubahan data yang diberitahukan dengan tepat, tampilan daur ulang akan menganimasikan tampilan. Saat menambahkan item, area yang akan diisi dengan item baru dibuat, dengan item baru memudar. Penghapusan adalah sebaliknya. Yang perlu Anda lakukan selain hal-hal adaptor adalah mengatur gaya tampilan Anda untuk menyampaikan struktur logis kepada pengguna.

Pembaruan: Ryan Brooks sekarang telah menulis artikel tentang cara melakukan ini.

Tonic Artos
sumber
Saran bagus. Bertanya-tanya mengapa tidak ada orang lain yang memilih jawaban ini !!
x-treme
Saya akan melihat tentang menambahkan ini sebagai contoh ke SuperSLiM sebagai bagian dari rilis berikutnya.
Tonic Artos
Ryan Brooks sekarang telah menulis artikel tentang bagaimana melakukan ini.
Tonic Artos
Saran bagus. Mengapa jawaban ini sangat jauh ke bawah sehingga saya harus menggulir ke bawah untuk menemukannya? Ini harus ditampilkan di bagian paling atas sehingga lebih banyak orang dapat menemukan jawaban yang indah ini dengan lebih mudah.
RestInPeace
1
Ryan Brooks menandai perpustakaannya sebagai usang. Saya ingin tahu apakah hanya karena dia berhenti mendukungnya atau ternyata pendekatan ini merusak sesuatu atau menciptakan kebocoran memori atau ...
Varvara Kalinina
6

Dapatkan implementasi kode sampel dari sini

Setel ValueAnimator di dalam onClick dari ViewHolder

@Override
public void onClick(final View view) {
    if (mOriginalHeight == 0) {
        mOriginalHeight = view.getHeight();
    }
    ValueAnimator valueAnimator;
    if (!mIsViewExpanded) {
        mIsViewExpanded = true;
        valueAnimator = ValueAnimator.ofInt(mOriginalHeight, mOriginalHeight + (int) (mOriginalHeight * 1.5));
    } else {
        mIsViewExpanded = false;
        valueAnimator = ValueAnimator.ofInt(mOriginalHeight + (int) (mOriginalHeight * 1.5), mOriginalHeight);
    }
    valueAnimator.setDuration(300);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        public void onAnimationUpdate(ValueAnimator animation) {
            Integer value = (Integer) animation.getAnimatedValue();
            view.getLayoutParams().height = value.intValue();
            view.requestLayout();
        }
    });
    valueAnimator.start();

}

Ini kode terakhirnya

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private TextView mFriendName;
    private int mOriginalHeight = 0;
    private boolean mIsViewExpanded = false;


    public ViewHolder(RelativeLayout v) {
        super(v);
        mFriendName = (TextView) v.findViewById(R.id.friendName);
        v.setOnClickListener(this);
    }

    @Override
    public void onClick(final View view) {
        if (mOriginalHeight == 0) {
            mOriginalHeight = view.getHeight();
        }
        ValueAnimator valueAnimator;
        if (!mIsViewExpanded) {
            mIsViewExpanded = true;
            valueAnimator = ValueAnimator.ofInt(mOriginalHeight, mOriginalHeight + (int) (mOriginalHeight * 1.5));
        } else {
            mIsViewExpanded = false;
            valueAnimator = ValueAnimator.ofInt(mOriginalHeight + (int) (mOriginalHeight * 1.5), mOriginalHeight);
        }
        valueAnimator.setDuration(300);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                view.getLayoutParams().height = value.intValue();
                view.requestLayout();
            }
        });
        valueAnimator.start();

    }
}
Kavin Varnan
sumber
11
Ini tidak berfungsi "seperti ExpandableListView", karena konten yang diperluas dalam kasus tersebut adalah daftar itu sendiri dengan item yang berasal dari adaptor. Ini adalah solusi yang merosot dengan hanya 1 item yang diperbolehkan sebagai anak-anak di dalam grup.
TWiStErRob
juga tidak berfungsi sebagaimana mestinya dengan tampilan yang didaur ulang sama sekali
ambil
Ini tidak berfungsi dengan baik karena tampilan di RecyclerList mungkin diulang beberapa kali, jadi saat Anda memperluas satu item, Anda melihat beberapa item di daftar tersebut diperluas
Hossein Shahdoost
3

https://github.com/gabrielemariotti/cardslib

Library ini memiliki implementasi daftar yang dapat diperluas dengan recyclerview (lihat aplikasi demo di bawah "CardViewNative" -> "List, Grid, and RecyclerView" -> "Kartu yang dapat diperluas"). Ini juga memiliki banyak kombinasi kartu / daftar keren lainnya.

Xinzz
sumber
2
Daftar Kartu yang Dapat Diperluas ini bukanlah turunan dari RecyclerView (tidak memperluas RecyclerView, ini hanya memperluas ExpandableListVIew)
whizzzkey
0

Seseorang mengeluh tentang solusi yang disebutkan di atas tidak dapat digunakan dengan listview sebagai konten yang dapat diperluas. Tetapi ada solusi sederhana: buat listview dan isi listview ini secara manual dengan baris Anda .

Solusi untuk yang malas: ada solusi sederhana jika Anda tidak ingin terlalu banyak mengubah kode. Cukup gunakan adaptor Anda secara manual untuk membuat tampilan dan menambahkannya ke LinearLayout.

Berikut contohnya:

if (mIsExpanded)
{
    // llExpandable... is the expandable nested LinearLayout
    llExpandable.removeAllViews();
    final ArrayAdapter<?> adapter = ... // create your adapter as if you would use it for a ListView
    for (int i = 0; i < adapter.getCount(); i++)
    {
        View item = adapter.getView(i, null, null);
        // if you want the item to be selectable as if it would be in a default ListView, then you can add following code as well:
        item.setBackgroundResource(Functions.getThemeReference(context, android.R.attr.selectableItemBackground));
        item.setTag(i);
        item.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // item would be retrieved with: 
                // adapter.getItem((Integer)v.getTag())
            }
        });
        llExpandable.addView(item);
    }
    ExpandUtils.expand(llExpandable, null, 500);
}
else
{
    ExpandUtils.collapse(llExpandable, null, 500);
}

fungsi pembantu: getThemeReference

public static int getThemeReference(Context context, int attribute)
{
    TypedValue typeValue = new TypedValue();
    context.getTheme().resolveAttribute(attribute, typeValue, false);
    if (typeValue.type == TypedValue.TYPE_REFERENCE)
    {
        int ref = typeValue.data;
        return ref;
    }
    else
    {
        return -1;
    }
}

kelas helper: ExpandUtils

Kavin Varnan sudah memposting cara menganimasikan tata letak ... Tetapi jika Anda ingin menggunakan kelas saya, silakan melakukannya, saya memposting intinya: https://gist.github.com/MichaelFlisar/738dfa03a1579cc7338a

prom85
sumber
9
"Solusi Malas" adalah ide yang sangat buruk. Menambahkan tampilan ke linearlayout di dalam tampilan yang dapat di-scroll sangat tidak efisien.
Matius
Saya pikir itu setidaknya lebih dari berguna. Bekerja cepat dan lancar di semua perangkat yang saya uji. Ngomong-ngomong, tampilan ditambahkan saat listview tidak terlihat ... hanya tampilan daftar yang sudah terisi yang akan ditampilkan ...
prom85
Ini rapi! Terima kasih banyak
Pawan Kumar
1
Seperti yang disebutkan @Matthew, ini sebenarnya bukan ide yang bagus. Memiliki satu tampilan besar yang dapat di-scroll dengan LinearLayouts tidak berskala dengan baik. Salah satu alasan terbesar RecyclerView / ListView dan tampilan serupa lainnya ditulis adalah untuk mengoptimalkan memiliki daftar besar yang didukung data dengan ukuran tidak diketahui. Membangun satu tampilan dengan sekelompok tampilan yang ditambahkan membuang semua pengoptimalan yang disediakan. Tampilan daur ulang adalah manfaat besar dan membuat memori aplikasi Anda efisien. Kecuali jika jumlah itemnya kecil, ada banyak pekerjaan yang disimpan dengan menggunakan daftar untuk menangani pengikatan tampilan.
munkay
Anda benar sekali, tentu saja ini tidak sempurna dan tidak mengoptimalkan apa pun ... Untuk penggunaan saya, saya selalu hanya punya beberapa item ... Jadi ini tidak masalah ... Btw, sementara itu saya menemukan cara untuk dilihat pendaur ulang bersarang ... Hanya menggunakan tinggi tetap horisontal pandangan pendaur ulang (tidak sempurna untuk setiap usecase, tapi masih) sebagai bersarang recyclerviewdan Anda dapat memperluas / menyembunyikan satu bersarang ini dan menggunakan semua optimisations darirecyclerview
prom85
0

Anda dapat menggunakan ExpandableLayout yang menyukai kotak centang animasi luaskan / ciutkan yang mulus, sehingga Anda dapat menggunakannya sebagai Kotak Centang di ListView dan RecyclerView.

https://github.com/KyoSherlock/ExpandableLayout

pengguna2914737
sumber
0

Ini adalah kode contoh untuk apa yang disebutkan oleh @TonicArtos untuk menambah dan menghapus Item dan untuk menganimasikannya saat melakukannya, ini diambil dari contoh RecyclerView Animations dan GitHub

1) Tambahkan Listener di dalam onCreateViewHolder () Anda untuk mendaftar onClick

2) Buat OnClickListener kustom Anda di dalam Adapter Anda

private View.OnClickListener mItemListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        TextView tv = (TextView) v.findViewById(R.id.tvItems);
        String selected = tv.getText().toString();
        boolean checked = itemsList.get(recyclerView.getChildAdapterPosition(v)).isChecked();

        switch (selected){
            case "Item1":
                if(checked){
                    deleteItem(v);
                    itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(false);
                }else {
                    addItem(v);
                    itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(true);
                }
                break;
            case "Item2":
                if(checked){
                    deleteItem(v);
                    itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(false);
                }else {
                    addItem(v);
                    itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(true);
                }
                break;                 
            default:
                //In my case I have checkList in subItems,
                //checkItem(v);
                break;
        }
    }
};

3) Tambahkan addItem () dan deleteItem () Anda

private void addItem(View view){
    int position = recyclerView.getChildLayoutPosition(view);
    if (position != RecyclerView.NO_POSITION){
        navDrawItems.add(position+1,new mObject());
        navDrawItems.add(position+2,new mObject());
        notifyItemRangeInserted(position+1,2);
    }
}


private void deleteItem(View view) {
    int position = recyclerView.getChildLayoutPosition(view);
    if (position != RecyclerView.NO_POSITION) {
        navDrawItems.remove(position+2);
        navDrawItems.remove(position+1);
        notifyItemRangeRemoved(position+1,2);
    }
}

4) Jika RecyclerViewAdapter Anda tidak dalam Aktivitas yang sama dengan Recycler View , teruskan instance recyclerView ke Adapter saat membuat

5) itemList adalah ArrayList berjenis mObject yang membantu mempertahankan status item (Buka / Tutup), nama, jenis Item (subItems / mainItem) dan mengatur Tema berdasarkan nilai

public class mObject{
    private String label;
    private int type;
    private boolean checked;
} 
Ujju
sumber