今天工作的时候遇到一个需求,需要实现多行多列单选,并且点击变色的功能,一开始我是想用RadioButton来实现的,但是RadioGroup只能是单行纵向或者横向,如果要实现多行多列的话,必须自定义一个RadioGroup,最终我还是选择用RecyclerView来实现。
思路
1、首先自定义一个适配器,将列表的子项的布局设置好,并设置好点击事件,同时定义一个Map用来存储每个子项的ViewHolder,在Adapter中定义一个函数,用来实现子项点击后刷新自身背景的功能;
2、RecyclerView设置布局管理器为网格布局管理器GridLayoutManager,设置adapter的点击事件,设置间距
实现
自定义Adapter
public class FilterBureauAdapter extends RecyclerView.Adapter<FilterBureauAdapter.FilterBureauHolder> {
private Context mContext;
private String[] mList;
private Map<Integer,FilterBureauHolder> mHolderMap;
public FilterBureauAdapter(Context context, @NonNull String[] list) {
mContext = context;
mList = list;
mHolderMap = new HashMap<>();
}
@Override
public FilterBureauHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.list_item_filter_bureau,parent,false);
FilterBureauHolder holder = new FilterBureauHolder(view);
return holder;
}
@Override
public int getItemCount() {
return mList.length;
}
@Override
public void onBindViewHolder(final FilterBureauHolder holder, final int position) {
holder.btnBureau.setText(mList[position]);
holder.btnBureau.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(v,position);
}
});
// 保存子项的ViewHolder
mHolderMap.put(position,holder);
}
/**
* 刷新区局按钮点击状态
*/
public void refreshBureau(int position){
for (Map.Entry<Integer,FilterBureauHolder> entry: mHolderMap.entrySet()) {
FilterBureauHolder holder = entry.getValue();
// 点击项背景以及字体变色,其它项背景及字体设置为默认颜色
if (entry.getKey() == position){
holder.btnBureau.setBackgroundResource(R.mipmap.icon_filterbox_on);
holder.btnBureau.setTextColor(mContext.getResources().getColor(R.color.main_blue));
} else {
holder.btnBureau.setBackgroundResource(R.mipmap.icon_filterbox_off);
holder.btnBureau.setTextColor(mContext.getResources().getColor(R.color.main_gray));
}
}
}
class FilterBureauHolder extends RecyclerView.ViewHolder{
Button btnBureau;
public FilterBureauHolder(View itemView) {
super(itemView);
btnBureau = (Button) itemView.findViewById(R.id.btn_bureau);
}
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}
其中OnItemClickListener 为自定义的接口
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
布局文件比较简单,就放了一个按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_bureau"
android:layout_width="60dp"
android:layout_height="32dp"
android:background="@mipmap/icon_filterbox_off"
android:textColor="@color/main_gray"/>
</LinearLayout>
然后就在Fragment中实例一个RecyclerView,设置好布局管理器、间距、适配器以及每一项的点击事件,这里我设置为网格布局,3列,然后设置子项间的间距为16dp
public void initFilterBureau() {
rvBbureau.setLayoutManager(new GridLayoutManager(getActivity(),3,GridLayoutManager.VERTICAL,false));
rvBbureau.addItemDecoration(new GridSpacingItemDecoration(3, Util.dip2px(getActivity(),16),true));
final FilterBureauAdapter adapter = new FilterBureauAdapter(getActivity(), Constant.BUREAUS);
adapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// 点击项后刷新每一项的背景及字体颜色
adapter.refreshBureau(position);
}
@Override
public void onItemLongClick(View view, int position) {
}
});
rvBbureau.setAdapter(adapter);
}
这里的间距设置是需要自定义的
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount) { // top edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}
以上就是所有的实现过程了
网友评论