Android RecyclerView(超简单)实现可展开列表——单项展开

2023-05-16

        之前写过  Android -- RecyclerView(超简单)实现可展开列表  的一篇文章,通过增加、删除的方式来模拟实现展开、收起的功能,思路很简单,也比较实用,最近看到评论里有猿友提出只展开一行的需求,并且还有猿友跟着提问,索性就再专门写一篇。

        只展开一行,也就是说当有一行处于展开的情况下再点击另外一行,另外一行展开,原本展开的那一行收起。好了,需求明确了,那我们要如何实现呢?

        最简单的方法就是标记展开的item,将当前展开的item标记(也可以说是封装保存起来)。多说无用,上码:

        注意:此篇是在之前写过的那篇文章的基础上拓展的,以下代码为根据需求修改的代码,没看过原篇的建议先看这篇

       先看效果图:

       

代码改动不多,首先我们需要再定义一个类:

public class ItemData {
    public DataBean dataBean;//数据类
    public View view;//展开的item,一定要将view一起封装起来,否则会有问题的。

    public DataBean getDataBean() {
        return dataBean;
    }

    public void setDataBean(DataBean dataBean) {
        this.dataBean = dataBean;
    }

    public View getView() {
        return view;
    }

    public void setView(View view) {
        this.view = view;
    }
}
封装

import java.util.ArrayList;
import java.util.List;

/**
 * Created by hbh on 2017/8/15.
 * 封装item 及 增删操作
 */

public class EncapsulationItem {
    public static List<ItemData> lastBeanList = new ArrayList<>();
    //将展开的item添加到list中
    public static void addLastBeanData(ItemData beanData){
        lastBeanList.add(beanData);
    }
    //清空list
    public static void cleraListBeanData(){
        lastBeanList.clear();
    }
}
这里用List作为容器。

import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.hbh.cl.expandrecyclerviewdemo.R;
import com.hbh.cl.expandrecyclerviewdemo.model.DataBean;
import com.hbh.cl.expandrecyclerviewdemo.util.ItemData;
import com.hbh.cl.expandrecyclerviewdemo.util.EncapsulationItem;

/**
 * Created by hbh on 2017/4/20.
 * 父布局ViewHolder
 */

public class ParentViewHolder extends BaseViewHolder {

    private Context mContext;
    private View view;
    private RelativeLayout containerLayout;
    private TextView parentLeftView;
    private TextView parentRightView;
    private ImageView expand;
    private View parentDashedView;
    private ItemData itemData;

    public ParentViewHolder(Context context, View itemView) {
        super(itemView);
        this.mContext = context;
        this.view = itemView;
    }

    public void bindView(final DataBean dataBean, final int pos, final ItemClickListener listener){

        containerLayout = (RelativeLayout) view.findViewById(R.id.container);
        parentLeftView = (TextView) view.findViewById(R.id.parent_left_text);
        parentRightView = (TextView) view.findViewById(R.id.parent_right_text);
        expand = (ImageView) view.findViewById(R.id.expend);
        parentDashedView = view.findViewById(R.id.parent_dashed_view);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) expand
                .getLayoutParams();
        expand.setLayoutParams(params);
        parentLeftView.setText(dataBean.getParentLeftTxt());
        parentRightView.setText(dataBean.getParentRightTxt());

        if (dataBean.isExpand()) {
            expand.setRotation(90);
            parentDashedView.setVisibility(View.INVISIBLE);
        } else {
            expand.setRotation(0);
            parentDashedView.setVisibility(View.VISIBLE);
        }

        //父布局OnClick监听
        containerLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    itemData = new ItemData();
                    if (EncapsulationItem.lastBeanList.size() > 0 && !EncapsulationItem.lastBeanList.get(0).getDataBean().getID().equals(dataBean.getID())) {
                        //如果有展开的item,先关闭
                        listener.onHideChildren(EncapsulationItem.lastBeanList.get(0).getDataBean());
                        EncapsulationItem.lastBeanList.get(0).getView().findViewById(R.id.parent_dashed_view).setVisibility(View.VISIBLE);
                        EncapsulationItem.lastBeanList.get(0).getDataBean().setExpand(false);
                        rotationExpandIcon(90, 0, EncapsulationItem.lastBeanList.get(0).getView().findViewById(R.id.expend));
                        EncapsulationItem.cleraListBeanData();//清空集合
                    }

                    if (dataBean.isExpand()) {
                        listener.onHideChildren(dataBean);
                        parentDashedView.setVisibility(View.VISIBLE);
                        EncapsulationItem.cleraListBeanData();
                        dataBean.setExpand(false);
                        rotationExpandIcon(90, 0, expand);
                    } else {
                        listener.onExpandChildren(dataBean);
                        itemData.setDataBean(dataBean);
                        itemData.setView(view);
                        EncapsulationItem.addLastBeanData(itemData);
                        parentDashedView.setVisibility(View.INVISIBLE);
                        dataBean.setExpand(true);
                        rotationExpandIcon(0, 90, expand);
                    }
                }
            }
        });
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void rotationExpandIcon(float from, float to, final View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to);//属性动画
            valueAnimator.setDuration(500);
            valueAnimator.setInterpolator(new DecelerateInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    view.setRotation((Float) valueAnimator.getAnimatedValue());
                }
            });
            valueAnimator.start();
        }
    }
}
这段代码中主要就是改动了父布局OnClick监听那一块,当我们点击父布局展开的时候先判断有没有展开状态的item,如果有,则先关闭,并清空List。然后在后面是否展开的判断中对List操作,很简单,就是展开增加、收起清除,一看就明白。

最后建议把滚动监听给去掉,实则没什么卵用,还会因为RecyclerView的复用出现问题,当向上滚动时,底部会闪现当前展开的item,虽然不会出现什么问题。

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.hbh.cl.expandrecyclerviewdemo.R;
import com.hbh.cl.expandrecyclerviewdemo.model.DataBean;

import java.util.List;

/**
 * Created by hbh on 2017/4/20.
 * 适配器
 */

public class RecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {

    private Context context;
    private List<DataBean> dataBeanList;
    private LayoutInflater mInflater;
    private OnScrollListener mOnScrollListener;

    public RecyclerAdapter(Context context, List<DataBean> dataBeanList) {
        this.context = context;
        this.dataBeanList = dataBeanList;
        this.mInflater = LayoutInflater.from(context);
    }

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = null;
        switch (viewType){
            case DataBean.PARENT_ITEM:
                view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
                return new ParentViewHolder(context, view);
            case DataBean.CHILD_ITEM:
                view = mInflater.inflate(R.layout.recycleview_item_child, parent, false);
                return new ChildViewHolder(context, view);
            default:
                view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
                return new ParentViewHolder(context, view);
        }
    }

    /**
     * 根据不同的类型绑定View
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        switch (getItemViewType(position)){
            case DataBean.PARENT_ITEM:
                ParentViewHolder parentViewHolder = (ParentViewHolder) holder;
                parentViewHolder.bindView(dataBeanList.get(position), position, itemClickListener);
                break;
            case DataBean.CHILD_ITEM:
                ChildViewHolder childViewHolder = (ChildViewHolder) holder;
                childViewHolder.bindView(dataBeanList.get(position), position);
                break;
        }
    }

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

    @Override
    public int getItemViewType(int position) {
        return dataBeanList.get(position).getType();
    }

    private ItemClickListener itemClickListener = new ItemClickListener() {
        @Override
        public void onExpandChildren(DataBean bean) {
            int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
            DataBean children = getChildDataBean(bean);//获取要展示的子布局数据对象,注意区分onHideChildren方法中的getChildBean()。
            if (children == null) {
                return;
            }
            add(children, position + 1);//在当前的item下方插入
            if (position == dataBeanList.size() - 2 && mOnScrollListener != null) { //如果点击的item为最后一个
//                mOnScrollListener.scrollTo(position + 1);//向下滚动,使子布局能够完全展示
            }
        }

        @Override
        public void onHideChildren(DataBean bean) {
            int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
            DataBean children = bean.getChildBean();//获取子布局对象
            if (children == null) {
                return;
            }
            remove(position + 1);//删除
            if (mOnScrollListener != null) {
//                mOnScrollListener.scrollTo(position);
            }
        }
    };

    /**
     * 在父布局下方插入一条数据
     * @param bean
     * @param position
     */
    public void add(DataBean bean, int position) {
        dataBeanList.add(position, bean);
        notifyItemInserted(position);
    }

    /**
     *移除子布局数据
     * @param position
     */
    protected void remove(int position) {
        dataBeanList.remove(position);
        notifyItemRemoved(position);
    }

    /**
     * 确定当前点击的item位置并返回
     * @param uuid
     * @return
     */
    protected int getCurrentPosition(String uuid) {
        for (int i = 0; i < dataBeanList.size(); i++) {
            if (uuid.equalsIgnoreCase(dataBeanList.get(i).getID())) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 封装子布局数据对象并返回
     * 注意,此处只是重新封装一个DataBean对象,为了标注Type为子布局数据,进而展开,展示数据
     * 要和onHideChildren方法里的getChildBean()区分开来
     * @param bean
     * @return
     */
    private DataBean getChildDataBean(DataBean bean){
        DataBean child = new DataBean();
        child.setType(1);
        child.setParentLeftTxt(bean.getParentLeftTxt());
        child.setParentRightTxt(bean.getParentRightTxt());
        child.setChildLeftTxt(bean.getChildLeftTxt());
        child.setChildRightTxt(bean.getChildRightTxt());
        return child;
    }

    /**
     * 滚动监听接口
     */
    public interface OnScrollListener{
        void scrollTo(int pos);
    }

    public void setOnScrollListener(OnScrollListener onScrollListener){
        this.mOnScrollListener = onScrollListener;
    }
}

好了,就那么多,改动很少,代码就不上传了,下载下来之前 github上的代码,然后直接拷过去替换掉就可以了。

有问题,欢迎来砸。

收工。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android RecyclerView(超简单)实现可展开列表——单项展开 的相关文章

随机推荐