创build一个可扩展的RecyclerView

我正在尝试执行一个像我的草图如下的回收站:

在这里输入图像说明

这个想法是,有一个父列表,当父列表中的列表项被点击,该列表项显示一个包含它自己的数据的子列表。 当在子列表中轻敲列表项时,该子项的值将被反映,并更新父项列表项中父项的值。

我试图让它在过去三天工作无济于事。 我尝试使用AdvancedReyclerview库,但对于像我这样的初学者来说,这是一个巨大的混乱的东西,尤其是在传递数据时没有意义。 我复制并粘贴了我需要的最小工作版本的文件,但我不知道如何将数据传递到recyclerview,以及如何使用新select的值更新它。

甚至有可能做我想做的事情,还是我在这里深深地陷入了困境?

如果还是难以理解的话,我可以多解释一下。

编辑:有人build议我这样做与ExpandableListView而不是RecyclerView。 对此有什么想法?

Solutions Collecting From Web of "创build一个可扩展的RecyclerView"

你可以在这里查看我的图书馆

并创build如下代码:

public class PurchaseItemRecyclerViewAdapter extends ExpandableRecyclerView.Adapter<PurchaseItemRecyclerViewAdapter.ChildViewHolder,ExpandableRecyclerView.SimpleGroupViewHolder,String,String> { List<ItemModel> itemModels; public PurchaseItemRecyclerViewAdapter() { this.itemModels = new ArrayList<>(); itemModels.add(new ItemModel("group 0",3,"subitem :")); itemModels.add(new ItemModel("group 1",3,"subitem :")); itemModels.add(new ItemModel("group 2",2,"subitem :")); itemModels.add(new ItemModel("group 3",1,"subitem :")); itemModels.add(new ItemModel("group 4",3,"subitem :")); itemModels.add(new ItemModel("group 5",5,"subitem :")); } @Override public int getGroupItemCount() { return itemModels.size(); } @Override public int getChildItemCount(int i) { return itemModels.get(i).getSubItemCount(); } @Override public String getGroupItem(int i) { return itemModels.get(i).getParentName(); } @Override public String getChildItem(int group, int child) { return itemModels.get(group).getSubItemPrefix() + child; } @Override protected ExpandableRecyclerView.SimpleGroupViewHolder onCreateGroupViewHolder(ViewGroup parent) { return new ExpandableRecyclerView.SimpleGroupViewHolder(parent.getContext()); } @Override protected ChildViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) { View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.purchase_list_content,parent,false); return new ChildViewHolder(rootView); } @Override public void onBindGroupViewHolder(ExpandableRecyclerView.SimpleGroupViewHolder holder, int group) { super.onBindGroupViewHolder(holder, group); holder.setText(getGroupItem(group)); } @Override public void onBindChildViewHolder(ChildViewHolder holder, final int group, int position) { super.onBindChildViewHolder(holder, group, position); holder.name.setText(getChildItem(group, position)); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { itemModels.get(group).setParentName("edited Parent"); notifyItemChanged(group); } }); } @Override public int getChildItemViewType(int i, int i1) { return 1; } public class ChildViewHolder extends RecyclerView.ViewHolder { private TextView name; public ChildViewHolder(View itemView) { super(itemView); name = (TextView) itemView.findViewById(R.id.item_name); } } } 

和这个ItemModel类:

 public class ItemModel { String parentName; int subItemCount; String subItemPrefix; public ItemModel(String parentName, int subItemCount, String subItemPrefix) { this.parentName = parentName; this.subItemCount = subItemCount; this.subItemPrefix = subItemPrefix; } public String getParentName() { return parentName; } public void setParentName(String parentName) { this.parentName = parentName; } public int getSubItemCount() { return subItemCount; } public void setSubItemCount(int subItemCount) { this.subItemCount = subItemCount; } public String getSubItemPrefix() { return subItemPrefix; } public void setSubItemPrefix(String subItemPrefix) { this.subItemPrefix = subItemPrefix; } } 

1.ExpandableRecyclerAdapter.class

 public abstract class ExpandableRecyclerAdapter<T extends ExpandableRecyclerAdapter.ListItem> extends RecyclerView.Adapter<ExpandableRecyclerAdapter.ViewHolder> { protected Context mContext; protected List<T> allItems = new ArrayList<>(); protected List<T> visibleItems = new ArrayList<>(); private List<Integer> indexList = new ArrayList<>(); private SparseIntArray expandMap = new SparseIntArray(); private int mode; protected static final int TYPE_HEADER = 1000; private static final int ARROW_ROTATION_DURATION = 150; public static final int MODE_NORMAL = 0; public static final int MODE_ACCORDION = 1; public ExpandableRecyclerAdapter(Context context) { mContext = context; } public static class ListItem { public int ItemType; public ListItem(int itemType) { ItemType = itemType; } } @Override public long getItemId(int i) { return i; } @Override public int getItemCount() { return visibleItems == null ? 0 : visibleItems.size(); } protected View inflate(int resourceID, ViewGroup viewGroup) { return LayoutInflater.from(mContext).inflate(resourceID, viewGroup, false); } public class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View view) { super(view); } } public class HeaderViewHolder extends ViewHolder { ImageView arrow; public HeaderViewHolder(View view) { super(view); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { toggleExpandedItems(getLayoutPosition(),false); /*if(isExpanded(getLayoutPosition())){ collapseItems(getLayoutPosition(),false); }else { expandItems(getLayoutPosition(),true); }*/ } }); } public HeaderViewHolder(View view, final ImageView arrow) { super(view); this.arrow = arrow; arrow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handleClick(); } }); } protected void handleClick() { if (toggleExpandedItems(getLayoutPosition(), false)) { openArrow(arrow); } else { closeArrow(arrow); } } public void bind(int position) { arrow.setRotation(isExpanded(position) ? 90 : 0); } } public boolean toggleExpandedItems(int position, boolean notify) { if (isExpanded(position)) { collapseItems(position, notify); return false; } else { expandItems(position, notify); if (mode == MODE_ACCORDION) { collapseAllExcept(position); } return true; } } public void expandItems(int position, boolean notify) { int count = 0; int index = indexList.get(position); int insert = position; for (int i=index+1; i<allItems.size() && allItems.get(i).ItemType != TYPE_HEADER; i++) { insert++; count++; visibleItems.add(insert, allItems.get(i)); indexList.add(insert, i); } notifyItemRangeInserted(position + 1, count); int allItemsPosition = indexList.get(position); expandMap.put(allItemsPosition, 1); if (notify) { notifyItemChanged(position); } } public void collapseItems(int position, boolean notify) { int count = 0; int index = indexList.get(position); for (int i=index+1; i<allItems.size() && allItems.get(i).ItemType != TYPE_HEADER; i++) { count++; visibleItems.remove(position + 1); indexList.remove(position + 1); } notifyItemRangeRemoved(position + 1, count); int allItemsPosition = indexList.get(position); expandMap.delete(allItemsPosition); if (notify) { notifyItemChanged(position); } } protected boolean isExpanded(int position) { int allItemsPosition = indexList.get(position); return expandMap.get(allItemsPosition, -1) >= 0; } @Override public int getItemViewType(int position) { return visibleItems.get(position).ItemType; } public void setItems(List<T> items) { allItems = items; List<T> visibleItems = new ArrayList<>(); expandMap.clear(); indexList.clear(); for (int i=0; i<items.size(); i++) { if (items.get(i).ItemType == TYPE_HEADER) { indexList.add(i); visibleItems.add(items.get(i)); } } this.visibleItems = visibleItems; notifyDataSetChanged(); } protected void removeItemAt(int visiblePosition) { int allItemsPosition = indexList.get(visiblePosition); allItems.remove(allItemsPosition); visibleItems.remove(visiblePosition); incrementIndexList(allItemsPosition, visiblePosition, -1); incrementExpandMapAfter(allItemsPosition, -1); notifyItemRemoved(visiblePosition); } private void incrementExpandMapAfter(int position, int direction) { SparseIntArray newExpandMap = new SparseIntArray(); for (int i=0; i<expandMap.size(); i++) { int index = expandMap.keyAt(i); newExpandMap.put(index < position ? index : index + direction, 1); } expandMap = newExpandMap; } private void incrementIndexList(int allItemsPosition, int visiblePosition, int direction) { List<Integer> newIndexList = new ArrayList<>(); for (int i=0; i<indexList.size(); i++) { if (i == visiblePosition) { if (direction > 0) { newIndexList.add(allItemsPosition); } } int val = indexList.get(i); newIndexList.add(val < allItemsPosition ? val : val + direction); } indexList = newIndexList; } public void collapseAll() { collapseAllExcept(-1); } public void collapseAllExcept(int position) { for (int i=visibleItems.size()-1; i>=0; i--) { if (i != position && getItemViewType(i) == TYPE_HEADER) { if (isExpanded(i)) { collapseItems(i, true); } } } } public void expandAll() { for (int i=visibleItems.size()-1; i>=0; i--) { if (getItemViewType(i) == TYPE_HEADER) { if (!isExpanded(i)) { expandItems(i, true); } } } } public static void openArrow(View view) { view.animate().setDuration(ARROW_ROTATION_DURATION).rotation(180); } public static void closeArrow(View view) { view.animate().setDuration(ARROW_ROTATION_DURATION).rotation(0); } public int getMode() { return mode; } public void setMode(int mode) { this.mode = mode; } } 

2.activity_main

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/main_recycler" android:layout_width="match_parent" android:layout_height="match_parent" /> 

3.item_header

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="@dimen/standard_padding"> <LinearLayout android:id="@+id/lnr_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true"> <TextView android:id="@+id/txt_header_address" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@mipmap/ic_usa" android:gravity="center" android:text="Beverly Hills" android:textStyle="bold" /> </LinearLayout> <ImageView android:id="@+id/img_arrow" android:layout_width="@dimen/arrow_size" android:layout_height="@dimen/arrow_size" android:layout_alignParentRight="true" android:src="@mipmap/arrow" /> <TextView android:id="@+id/txt_header_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:text="Home" android:textStyle="bold" /> 

4.item_content.xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:orientation="vertical"> <RelativeLayout android:id="@+id/rcl_header_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <Button style="?android:attr/borderlessButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_cancle" /> <Button style="?android:attr/borderlessButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="@string/btn_save" /> </RelativeLayout> <LinearLayout android:id="@+id/lnr_parent" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/rcl_header_btn" android:gravity="center_vertical" android:orientation="vertical"> <EditText android:id="@+id/edt_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="DESCRIPTION" /> <EditText android:id="@+id/edt_address" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Address" /> <LinearLayout android:id="@+id/lnr_child_1" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/edt_city" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:hint="City" /> <EditText android:id="@+id/edt_state" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:hint="State" /> </LinearLayout> <LinearLayout android:id="@+id/lnr_child_2" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/edt_zipcode" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:hint="Zip Code" /> <EditText android:id="@+id/edt_country" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:hint="Country" /> </LinearLayout> </LinearLayout> <RelativeLayout android:id="@+id/rcl_bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/lnr_parent"> <CheckBox android:id="@+id/chk_marked" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/txt_type" /> <TextView android:id="@+id/txt_type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/btn_delete" android:layout_toRightOf="@+id/chk_marked" android:gravity="center" android:text="SET AS DEFAULT" /> <Button android:id="@+id/btn_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="DELETE" /> </RelativeLayout> 

5.Adapter

 public class PeopleAdapter extends ExpandableRecyclerAdapter<PeopleAdapter.PeopleListItem> { public static final int TYPE_PERSON = 1001; public PeopleAdapter(Context context) { super(context); setItems(getSampleItems()); } public static class PeopleListItem extends ExpandableRecyclerAdapter.ListItem { public String Text; public PeopleListItem(String group) { super(TYPE_HEADER); Text = group; } public PeopleListItem(String first, String last) { super(TYPE_PERSON); Text = first + " " + last; } } public class HeaderViewHolder extends ExpandableRecyclerAdapter.HeaderViewHolder { TextView name; public HeaderViewHolder(View view) { super(view, (ImageView) view.findViewById(R.id.img_arrow)); name = (TextView) view.findViewById(R.id.txt_header_name); } public void bind(int position) { super.bind(position); name.setText(visibleItems.get(position).Text); } } public class PersonViewHolder extends ExpandableRecyclerAdapter.ViewHolder { EditText name; public PersonViewHolder(View view) { super(view); name = (EditText) view.findViewById(R.id.edt_description); } public void bind(int position) { name.setText(name.getText()); } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HEADER: return new HeaderViewHolder(inflate(R.layout.item_header, parent)); case TYPE_PERSON: default: return new PersonViewHolder(inflate(R.layout.item_content, parent)); } } @Override public void onBindViewHolder(ExpandableRecyclerAdapter.ViewHolder holder, int position) { switch (getItemViewType(position)) { case TYPE_HEADER: ((HeaderViewHolder) holder).bind(position); break; case TYPE_PERSON: default: ((PersonViewHolder) holder).bind(position); break; } } private List<PeopleListItem> getSampleItems() { List<PeopleListItem> items = new ArrayList<>(); items.add(new PeopleListItem("Friends")); items.add(new PeopleListItem("", "")); items.add(new PeopleListItem("Friends")); items.add(new PeopleListItem("", "")); return items; } 

}

6.MainActivity.java

 public class MainActivity extends AppCompatActivity { RecyclerView recycler; PeopleAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); recycler = (RecyclerView) findViewById(R.id.main_recycler); adapter = new PeopleAdapter(this); adapter.setMode(ExpandableRecyclerAdapter.MODE_ACCORDION); recycler.setLayoutManager(new LinearLayoutManager(this)); recycler.setAdapter(adapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_expand_all: adapter.expandAll(); return true; case R.id.action_collapse_all: adapter.collapseAll(); return true; default: return super.onOptionsItemSelected(item); } } } 

你可以用这个库轻松实现,这里有一个完整的例子。

基本上你把你的项目分成几部分:

 class MySection extends StatelessSection { String header; List<String> list; boolean expanded = true; public MySection(String header, List<String> list) { // call constructor with layout resources for this Section header and items super(R.layout.section_header, R.layout.section_item); this.myHeader = header; this.myList = list; } @Override public int getContentItemsTotal() { return expanded? list.size() : 0; } @Override public RecyclerView.ViewHolder getHeaderViewHolder(View view) { return new HeaderViewHolder(view); } @Override public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) { final HeaderViewHolder headerHolder = (HeaderViewHolder) holder; headerHolder.tvTitle.setText(title); headerHolder.rootView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { expanded = !expanded; headerHolder.imgArrow.setImageResource( expanded ? R.drawable.ic_keyboard_arrow_up_black_18dp : R.drawable.ic_keyboard_arrow_down_black_18dp ); sectionAdapter.notifyDataSetChanged(); } }); } @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(list.get(position)); } } 

然后创build您的部分的实例,并设置您的适配器:

 // Create an instance of SectionedRecyclerViewAdapter SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter(); // Add your Sections sectionAdapter.addSection(new MySection("A", Arrays.asList(new String[] {"a", "b", "c" }))); sectionAdapter.addSection(new MySection("B", Arrays.asList(new String[] {"d", "e", "f" }))); // Set up your RecyclerView with the SectionedRecyclerViewAdapter RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(sectionAdapter); 

这有点晚,但看看这个先进recyclerview图书馆https://github.com/h6ah4i/android-advancedrecyclerview

在他们的文档中,您可以看到Expandable项目相关的类/接口检查出来。