创建一个可扩展的RecyclerView [英] Creating an expandable RecyclerView

查看:75
本文介绍了创建一个可扩展的RecyclerView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个行为与下面的草图类似的recyclerview:

I'm trying to implement a recyclerview that behaves like my sketch below:

这个想法是有一个父列表,当点击父列表中的一个列表项时,该列表项将显示一个包含其自身数据的子列表.在子级列表中点击列表项时,该子级的值会得到反映并更新父级列表项中父级的值.

The idea is that there is a parent list, when an list item in the parent list is tapped, that list item reveals a child list that contains it's own data. when a list item is tapped in the child list, the value of that child is reflected and updates the value of the parent in the parent list item.

在过去的3天里,我一直尝试使其正常运行,但无济于事.我尝试使用 AdvancedReyclerview库,但是对于像我这样的初学者来说,那是一堆乱七八糟的东西毫无意义,尤其是在传递数据时.我复制并粘贴了获得最低工作版本所需的文件,但是我不知道如何将数据传递到recyclerview以及如何使用新选择的值更新数据.

I've tried to get it working for the past 3 days to no avail. I tried using the AdvancedReyclerview library but to a beginner like me, it was a giant mess of things that didn't make sense especially when passing in the data. I copied and pasted files that I needed to get a minimal working version but I had no idea how to pass my data into the recyclerview and how to update it with the newly selected value.

是否有可能做我想做的事情,还是我超出了我的深度?

Is it even possible to do what I'm trying to do or am I way out of my depth here?

如果仍然难以理解,我可以进一步解释.

If it's still difficult to understand, I can explain it more.

有人建议我使用ExpandableListView而不是RecyclerView进行此操作.有什么想法吗?

someone recommended that I do this with the ExpandableListView rather than the RecyclerView. Any thoughts on that?

推荐答案

1.ExpandableRecyclerAdapter.class

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

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

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

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

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

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);
    }
}
}

这篇关于创建一个可扩展的RecyclerView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆