用RecyclerView写的城市列表
分享一下城市列表的网格布局样式的demo,代码里面包括网格布局和竖直列表布局两种样式。
网格样式:
image.png
竖直列表样式:
image.png-
数据来源,本地的citylist.json城市数据源如下截取,放在新建的raw文件夹下面:
[ { "key": "A", "list": [ { "realname": "澳门", "displayname": "澳门" }, { "realname": "阿勒泰地区", "displayname": "阿勒泰" }, { "realname": "安康", "displayname": "安康" }, { "realname": "安庆", "displayname": "安庆" }, { "realname": "安顺", "displayname": "安顺" }, { "realname": "安阳", "displayname": "安阳" }, { "realname": "鞍山", "displayname": "鞍山" } ] } ]
读取数据成String类型,在根据key关键词来解析数据。
public static String getFromRaw(Context context) {
String result = "";
try {
InputStream in = context.getResources().openRawResource(
R.raw.citylist);
// 获取文件的字节数
int lenght = in.available();
// 创建byte数组
byte[] buffer = new byte[lenght];
// 将文件中的数据读到byte数组中
in.read(buffer);
result = new String(buffer,"utf-8");
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
2.根据关键词Key来解析数据。设计的方法是一共多少个字母就有多少个Item。其中item里面在include一个RecyclerView的网格布 局和一个TextView来显示字母数据。所以在这里可以将解析的城市列表封装成一个Map数据,key对应的是字母,而value城市列表名则用list数组来封装,有多少个字母就新建对应的list来包含对应字母的所有城市名称,详见如下。(使用ArrayMap在数据量不大的情况下更省内存,性能更好):
//封装城市列表map集合
private ArrayMap<String, ArrayList<CityModel>> map = new ArrayMap<>();
//封装首字母list数组
private ArrayList<CityModel> nameSortsList = new ArrayList<>();
private void initData() {
String json = FileUtil.getFromRaw(this);
//解析数据
try {
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String nameSort = jsonObject.getString("key");
JSONArray jsonCityArray = jsonObject.getJSONArray("list");
CityModel cityModel = new CityModel();
cityModel.setNameScort(nameSort);
addMap(nameSort, jsonCityArray);
nameSortsList.add(cityModel);//封装字母列表数据成list
}
} catch (JSONException e) {
e.printStackTrace();
}
}
//添加到Map集合,key和解析的城市名组成的list相对应
private void addMap(String nameSort, JSONArray jsonCityArray) {
if (!map.containsKey(nameSort)) {
map.put(nameSort, new ArrayList<CityModel>());
}
for (int i = 0; i < jsonCityArray.length(); i++) {
CityModel cityModel = new CityModel();
try {
JSONObject jsonCityObject = jsonCityArray.getJSONObject(i);
String realName = jsonCityObject.getString("realname");
String displayName = jsonCityObject.getString("displayname");
cityModel.setCityName(displayName);
} catch (JSONException e) {
e.printStackTrace();
}
map.get(nameSort).add(cityModel);
}
}
3.数据封装好后,再写Adapter,这里参照网上大神封装Adapter的方法,写一个AbsAdapter来绑定ViewHolder,在写一个BaseAdapter继承AbsAdapter来封装数据;ViewHolder封装成BaseViewHolder,里面将Item对应的布局传入形成对应的View,再将不同的View封装成SparseArray的View数组,在里面findViewById找到对应填写数据的子布局。三个基类代码就不贴了,详见Github源码: https://github.com/yangfang521314/ListCity_RecyclerView_Demo。
整体Item的Adapter:
public class ItemAdapter extends BaseAdapter<CityModel, ItemViewHolder> {
private RecyclerItemClickListener.OnItemClickListener onItemListener;
private ArrayMap<String, ArrayList<CityModel>> map;
private Context mContext;
private String style;
public ItemAdapter(Context context) {
super(context);
mContext = context;
}
@Override
protected ItemViewHolder createItemViewHolder(ViewGroup parent, int viewType) {
ItemViewHolder viewHolder = new ItemViewHolder(parent, R.layout.item_city_layout);
return viewHolder;
}
@Override
protected void bindCustomViewHolder(ItemViewHolder holder, int position) {
holder.mNameSort.setText(data.get(position).getNameScort());
if (map.containsKey(data.get(position).getNameScort())) {
CityListAdapter cityAdapter = new CityListAdapter(mContext);
cityAdapter.setData(map.get(data.get(position).getNameScort()));
cityAdapter.setOnClickListener(onItemListener);
if(style.equals("grid")){//网格布局
holder.mRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 4));
holder.mRecyclerView.setAdapter(cityAdapter);
}
if(style.equals("list")){//竖直列表布局
holder.mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext,LinearLayoutManager.VERTICAL,false));
holder.mRecyclerView.setAdapter(cityAdapter);
}
}
}
@Override
public void setData(List<CityModel> list) {
data = list;
}
public void setCityName(ArrayMap<String, ArrayList<CityModel>> cityName) {
this.map = cityName;
}
public void setOnItmeListener(RecyclerItemClickListener.OnItemClickListener clickListener) {
this.onItemListener = clickListener;
}
public void setStyle(String style) {
this.style = style;//分两种类型
}
}
具体城市列表名的Adapter
public class CityListAdapter extends BaseAdapter<CityModel, ItemViewHolder> {
private RecyclerItemClickListener.OnItemClickListener onClickListener;
public CityListAdapter(Context context) {
super(context);
}
@Override
protected ItemViewHolder createItemViewHolder(ViewGroup parent, int viewType) {
return new ItemViewHolder(parent, R.layout.list_city_name);
}
@Override
protected void bindCustomViewHolder(final ItemViewHolder holder, final int position) {
holder.mCityName.setText(data.get(position).getCityName());
holder.mCityName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickListener.onItemClick(holder.mCityName,position);
}
});
}
public void setOnClickListener(RecyclerItemClickListener.OnItemClickListener onClickListener) {
this.onClickListener = onClickListener;
}
}
ItemViewHolder:
public class ItemViewHolder extends BaseViewHolder {
public TextView mNameSort;
public RecyclerView mRecyclerView;
public TextView mCityName;
public ItemViewHolder(ViewGroup parent, @LayoutRes int resId) {
super(parent, resId);
mNameSort = getView(R.id.header_tv);
mRecyclerView = getView(R.id.city_recyclerview);
mCityName = getView(R.id.tv_cityname);
}
}
4.主Activity代码:
public class GridCityActivity extends AppCompatActivity implements RecyclerItemClickListener.OnItemClickListener {
//封装城市列表数据
private ArrayMap<String, ArrayList<CityModel>> map = new ArrayMap<>();
//首字母数据
private ArrayList<CityModel> nameSortsList = new ArrayList<>();
private RecyclerView mRecyclerview;
private ItemAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_city_list);
Intent intent = getIntent();
String style = intent.getStringExtra("style");
initData();
initGridRecy(style);
}
private void initGridRecy(String style) {
mRecyclerview = (RecyclerView) findViewById(R.id.list_cyclerview);
mRecyclerview.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
adapter = new ItemAdapter(this);
adapter.setData(nameSortsList);
//列表和网格布局
adapter.setCityName(map);
adapter.setStyle(style);
adapter.setOnItmeListener(this);//自定义监听方法
mRecyclerview.setAdapter(adapter);
}
private void initData() {
String json = FileUtil.getFromRaw(this);
try {
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String nameSort = jsonObject.getString("key");
JSONArray jsonCityArray = jsonObject.getJSONArray("list");
CityModel cityModel = new CityModel();
cityModel.setNameScort(nameSort);
addMap(nameSort, jsonCityArray);
nameSortsList.add(cityModel);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private void addMap(String nameSort, JSONArray jsonCityArray) {
if (!map.containsKey(nameSort)) {
map.put(nameSort, new ArrayList<CityModel>());
}
for (int i = 0; i < jsonCityArray.length(); i++) {
CityModel cityModel = new CityModel();
try {
JSONObject jsonCityObject = jsonCityArray.getJSONObject(i);
String realName = jsonCityObject.getString("realname");
String displayName = jsonCityObject.getString("displayname");
cityModel.setCityName(displayName);
} catch (JSONException e) {
e.printStackTrace();
}
map.get(nameSort).add(cityModel);
}
}
@Override
public void onItemClick(View view, int position) {
Toast.makeText(this, ((TextView) view).getText(), Toast.LENGTH_LONG).show();//自定义监听
}
}
有错请指出,不吝赐教。
其他代码见GitHub:https://github.com/yangfang521314/ListCity_RecyclerView_Demo
如果你喜欢希望能顺手在Github点个star哦!谢谢!