之前写过 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上的代码,然后直接拷过去替换掉就可以了。
有问题,欢迎来砸。
收工。