98

新的 RecyclerView 可以使用可扩展的列表项吗?像 ExpandableListView 一样吗?

4

6 回答 6

129

使用库存的 LayoutManager 很容易做到这一点,这完全取决于您如何管理适配器。

当您想要扩展一个部分时,您只需在标题之后将新项目添加到您的适配器。请记住在执行此操作时调用 notifyItemRangeInserted。要折叠一个部分,您只需删除相关项目,然后调用 notifyItemRangeRemoved()。对于适当通知的任何数据更改,回收器视图将为视图设置动画。添加项目时,会创建一个要填充新项目的区域,新项目会淡入。删除则相反。除了适配器之外,您需要做的就是设置视图样式以将逻辑结构传达给用户。

更新:Ryan Brooks 现在写了一篇关于如何做到这一点的文章。

于 2015-03-20T10:29:23.767 回答
5

从这里获取示例代码实现

在 ViewHolder 的 onClick 内设置 ValueAnimator

@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();

}

这是最终代码

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

    }
}
于 2014-10-18T19:38:45.147 回答
3

https://github.com/gabrielemariotti/cardslib

这个库有一个带有 recyclerview 的可扩展列表的实现(请参阅“CardViewNative”->“List、Grid 和 RecyclerView”->“可扩展卡”下的演示应用程序)。它还有许多其他很酷的卡片/列表组合。

于 2015-02-01T20:52:51.690 回答
0

有人抱怨上述解决方案不适用于列表视图作为可扩展内容。但是有一个简单的解决方案:创建一个列表视图并使用您的 rows 手动填充此列表视图

懒惰者的解决方案:如果您不想过多地更改代码,有一个简单的解决方案。只需手动使用您的适配器创建视图并将它们添加到LinearLayout.

这是示例:

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

辅助函数: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;
    }
}

辅助类:ExpandUtils

Kavin Varnan postet 已经如何为布局设置动画......但如果你想使用我的课程,请随意这样做,我发布了一个要点:https ://gist.github.com/MichaelFlisar/738dfa03a1579cc7338a

于 2015-01-29T07:51:51.603 回答
0

您可以使用类似于平滑展开/折叠动画 CheckBox 的 ExpandableLayout,因此您可以将其用作 ListView 和 RecyclerView 中的 CheckBox。

https://github.com/KyoSherlock/ExpandableLayout

于 2015-07-29T01:20:23.777 回答
0

这是@TonicArtos提到的添加和删除项目并在执行时对其进行动画处理的示例代码,取自RecyclerView AnimationsGitHub 示例

1)在onCreateViewHolder()中添加监听器以注册 onClick

2)在您的适配器内创建您的自定义OnClickListener

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)添加您的 addItem() 和 deleteItem()

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) 如果您的 RecyclerViewAdapter 与 Recycler View 不在同一个 Activity 中,请在创建时将recyclerView的实例传递给 Adapter

5) itemList 是一个 mObject 类型的 ArrayList,有助于维护项目的状态(打开/关闭)、名称、项目类型(子项目/主项目)并根据值设置主题

public class mObject{
    private String label;
    private int type;
    private boolean checked;
} 
于 2016-10-25T15:02:38.670 回答