Recyclerview实现下拉列表

时间:2023-01-29 10:13:57

1.先导包    

compile 'com.android.support:recyclerview-v7:25.3.0'


2.主布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="exp.rusan.secondarylistdemo.MainActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
>

</android.support.v7.widget.RecyclerView>

</RelativeLayout>




3.item布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="8dp"
>

<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="item"
android:textSize="18sp"
/>

</LinearLayout>





4.给Recyclerview添加每个item的分割线    RvDividerItemDecoration

 
public class RvDividerItemDecoration extends RecyclerView.ItemDecoration{

public final String TAG = this.getClass().getSimpleName();

private static final int[] ATTRS = new int[] {
android.R.attr.listDivider
};

public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

private Drawable divider;

private int orientation;


public RvDividerItemDecoration(Context context, int orientation) {
final TypedArray typedArray = context.obtainStyledAttributes(ATTRS);
divider = typedArray.getDrawable(0);
typedArray.recycle();
setOrientation(orientation);
}

public void setOrientation(int pOrientation) {
if (pOrientation != HORIZONTAL_LIST && pOrientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
orientation = pOrientation;
}

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
// Log.v(TAG, "onDraw");

if (orientation == VERTICAL_LIST) {
drawForVertical(c, parent);
} else {
drawForHorizontal(c, parent);
}
}

//获取Item的位置,然后为每个item定位画线
private void drawForVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();

final int childCount = parent.getChildCount();
for ( int i = 0; i < childCount; i++ ) {
final View child = parent.getChildAt(i);
RecyclerView recyclerView = new RecyclerView(parent.getContext());
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}

private void drawForHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();

final int childCount = parent.getChildCount();
for ( int i = 0; i < childCount; i++ ) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

final int left = child.getRight() + params.rightMargin;
final int right = left + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}

@Override
//可以通过outRect()为每个Item设置一定的偏移量。
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (orientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, divider.getIntrinsicHeight());
} else {
outRect.set(0, 0, divider.getIntrinsicWidth(), 0);
}
}
}




5.给Recyclerview创建一个适配器  RecyclerAdapter

public class RecyclerAdapter extends SecondaryListAdapter<RecyclerAdapter.GroupItemViewHolder, RecyclerAdapter.SubItemViewHolder> {


private Context context;

private List<DataTree<String, String>> dts = new ArrayList<>();

public RecyclerAdapter(Context context) {
this.context = context;
}

public void setData(List datas) {
dts = datas;
notifyNewData(dts);
}

@Override
public RecyclerView.ViewHolder groupItemViewHolder(ViewGroup parent) {

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);

return new GroupItemViewHolder(v);
}

@Override
public RecyclerView.ViewHolder subItemViewHolder(ViewGroup parent) {

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);

return new SubItemViewHolder(v);
}

@Override
public void onGroupItemBindViewHolder(RecyclerView.ViewHolder holder, int groupItemIndex) {

((GroupItemViewHolder) holder).tvGroup.setText(dts.get(groupItemIndex).getGroupItem());

}

@Override
public void onSubItemBindViewHolder(RecyclerView.ViewHolder holder, int groupItemIndex, int subItemIndex) {

((SubItemViewHolder) holder).tvSub.setText(dts.get(groupItemIndex).getSubItems().get(subItemIndex));

}

@Override
public void onGroupItemClick(Boolean isExpand, GroupItemViewHolder holder, int groupItemIndex) {

Toast.makeText(context, "group item " + String.valueOf(groupItemIndex) + " is expand " +
String.valueOf(isExpand), Toast.LENGTH_SHORT).show();

}

@Override
public void onSubItemClick(SubItemViewHolder holder, int groupItemIndex, int subItemIndex) {

Toast.makeText(context, "sub item " + String.valueOf(subItemIndex) + " in group item " +
String.valueOf(groupItemIndex), Toast.LENGTH_SHORT).show();

}

public static class GroupItemViewHolder extends RecyclerView.ViewHolder {

TextView tvGroup;

public GroupItemViewHolder(View itemView) {
super(itemView);

tvGroup = (TextView) itemView.findViewById(R.id.tv);

}
}

public static class SubItemViewHolder extends RecyclerView.ViewHolder {

TextView tvSub;

public SubItemViewHolder(View itemView) {
super(itemView);

tvSub = (TextView) itemView.findViewById(R.id.tv);
}
}


}





6.再创建一个点击下拉列表的适配器    SecondaryListAdapter

public abstract class SecondaryListAdapter<GVH, SVH extends RecyclerView.ViewHolder> extends RecyclerView
.Adapter<RecyclerView.ViewHolder> {

private List<Boolean> groupItemStatus = new ArrayList<>();

private List<DataTree> dataTrees = new ArrayList<>();

/**
* Set new data for adapter to show. It must be called when set new data.
*
* @param data New data
*
*/
public void notifyNewData(List data) {
setDataTrees(data);
}


/**
* Set new data for adapter and notify changing.
*
* @param dt New data
*
*/
private final void setDataTrees(List dt) {
this.dataTrees = dt;
initGroupItemStatus(groupItemStatus);
notifyDataSetChanged();
}

/**
* Initialize the list to false.
*
* @param l The list need to initialize
*
*/
private void initGroupItemStatus(List l) {
for (int i = 0; i < dataTrees.size(); i++) {
l.add(false);
}
}


/**
* Create group item view holder for onCreateViewHolder.
*
* @param parent Provided by onCreateViewHolder.
*
*/
public abstract RecyclerView.ViewHolder groupItemViewHolder(ViewGroup parent);

/**
* Create subitem view holder for onCreateViewHolder.
*
* @param parent Provided by onCreateViewHolder.
*
*/
public abstract RecyclerView.ViewHolder subItemViewHolder(ViewGroup parent);


@Override
public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

RecyclerView.ViewHolder viewHolder = null;

if (viewType == ItemStatus.VIEW_TYPE_GROUPITEM) {

viewHolder = groupItemViewHolder(parent);

} else if (viewType == ItemStatus.VIEW_TYPE_SUBITEM) {

viewHolder = subItemViewHolder(parent);
}

return viewHolder;
}

/**
* Update the content of specified group item. The method will called by onBindViewHolder.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
*
* @param groupItemIndex The index of the group item.
*
*/
public abstract void onGroupItemBindViewHolder(RecyclerView.ViewHolder holder, int
groupItemIndex);

/**
* Update the content of specified subitem. The method will called by onBindViewHolder.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param subItemIndex The index of the subitem.
*
*/
public abstract void onSubItemBindViewHolder(RecyclerView.ViewHolder holder, int
groupItemIndex, int subItemIndex);

/**
* The method will be called when the group item clicked.
*
* @param isExpand whether is expanded or no the group item clicked.
* @param holder The holder' s item view clicked.
* @param groupItemIndex The index of the group item clicked.
*
*/
public abstract void onGroupItemClick(Boolean isExpand, GVH holder, int groupItemIndex);

/**
* The method will be called when the subitem clicked.
*
* @param holder The holder' s item view clicked.
* @param subItemIndex The index of the subitem clicked.
*
*/
public abstract void onSubItemClick(SVH holder, int groupItemIndex, int subItemIndex);

@Override
public final void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

final ItemStatus itemStatus = getItemStatusByPosition(position);

final DataTree dt = dataTrees.get(itemStatus.getGroupItemIndex());

if ( itemStatus.getViewType() == ItemStatus.VIEW_TYPE_GROUPITEM ) {

onGroupItemBindViewHolder(holder, itemStatus.getGroupItemIndex());

holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

int groupItemIndex = itemStatus.getGroupItemIndex();

if ( !groupItemStatus.get(groupItemIndex) ) {

onGroupItemClick(false, (GVH) holder, groupItemIndex);

groupItemStatus.set(groupItemIndex, true);
notifyItemRangeInserted(holder.getAdapterPosition() + 1, dt.getSubItems
().size());


} else {

onGroupItemClick(true, (GVH) holder, groupItemIndex);

groupItemStatus.set(groupItemIndex, false);
notifyItemRangeRemoved(holder.getAdapterPosition() + 1, dt.getSubItems
().size());

}

}
});

} else if (itemStatus.getViewType() == ItemStatus.VIEW_TYPE_SUBITEM) {

onSubItemBindViewHolder(holder, itemStatus.getGroupItemIndex(), itemStatus
.getSubItemIndex());

holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

onSubItemClick((SVH) holder, itemStatus.getGroupItemIndex(), itemStatus.getSubItemIndex());

}
});

}


}

@Override
public final int getItemCount() {

int itemCount = 0;

if (groupItemStatus.size() == 0) {
return 0;
}

for (int i = 0; i < dataTrees.size(); i++) {

if (groupItemStatus.get(i)) {
itemCount += dataTrees.get(i).getSubItems().size() + 1;
} else {
itemCount++;
}

}

return itemCount;
}


@Override
public final int getItemViewType(int position) {
return getItemStatusByPosition(position).getViewType();
}


/**
* Get item' s status include view type, group item index and subitem index.
*
* @param position Position
*
*/
private ItemStatus getItemStatusByPosition(int position) {

ItemStatus itemStatus = new ItemStatus();

int count = 0;
int i = 0;

for (i = 0; i < groupItemStatus.size(); i++ ) {

if (count == position) {

itemStatus.setViewType(ItemStatus.VIEW_TYPE_GROUPITEM);
itemStatus.setGroupItemIndex(i);
break;

} else if (count > position) {

itemStatus.setViewType(ItemStatus.VIEW_TYPE_SUBITEM);
itemStatus.setGroupItemIndex(i - 1);
itemStatus.setSubItemIndex(position - ( count - dataTrees.get(i - 1).getSubItems
().size() ) );
break;

}

count++;

if (groupItemStatus.get(i)) {

count += dataTrees.get(i).getSubItems().size();

}


}

if (i >= groupItemStatus.size()) {
itemStatus.setGroupItemIndex(i - 1);
itemStatus.setViewType(ItemStatus.VIEW_TYPE_SUBITEM);
itemStatus.setSubItemIndex(position - ( count - dataTrees.get(i - 1).getSubItems().size
() ) );
}

return itemStatus;
}



private static class ItemStatus {

public static final int VIEW_TYPE_GROUPITEM = 0;
public static final int VIEW_TYPE_SUBITEM = 1;

private int viewType;
private int groupItemIndex = 0;
private int subItemIndex = -1;

public ItemStatus() {
}

public int getViewType() {
return viewType;
}

public void setViewType(int viewType) {
this.viewType = viewType;
}

public int getGroupItemIndex() {
return groupItemIndex;
}

public void setGroupItemIndex(int groupItemIndex) {
this.groupItemIndex = groupItemIndex;
}

public int getSubItemIndex() {
return subItemIndex;
}

public void setSubItemIndex(int subItemIndex) {
this.subItemIndex = subItemIndex;
}
}


/**
* Created by Rusan on 2017/4/12.
*/

public final static class DataTree<K, V> {

private K groupItem;
private List<V> subItems;

public DataTree(K groupItem, List<V> subItems) {
this.groupItem = groupItem;
this.subItems = subItems;
}

public K getGroupItem() {
return groupItem;
}

public List<V> getSubItems() {
return subItems;
}
}
}





7.主函数

public class MainActivity extends AppCompatActivity {

private List<SecondaryListAdapter.DataTree<String, String>> datas = new ArrayList<>();


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setHasFixedSize(true);
rv.addItemDecoration(new RvDividerItemDecoration(this, LinearLayoutManager.VERTICAL));
RecyclerAdapter adapter = new RecyclerAdapter(this);
adapter.setData(datas);
rv.setAdapter(adapter);

}

{
List<String> group = new ArrayList<>();
for (int i = 0; i < 10; i++) {

datas.add(new SecondaryListAdapter.DataTree<String, String>(String.valueOf(i), new
ArrayList<String>(){{add("sub 0"); add("sub 1"); add("sub 2");}}));

}

}
}






8.最终效果如下图

Recyclerview实现下拉列表