版权声明:本文为博主原创文章,未经博主允许不得转载。
以前做的项目需要用到这样的一个界面,先发一张效果图,个人感觉还算可以,下面把我的实现过程记录一下。
首先,数据格式是这样的
很明显这个界面整体是一个listview,每个省是一个listitem,刚开始实现方法是在adapter的getview里动态的在每个listitem里添加LinearLayout,每一行城市就是一个LinearLayout,通过判断当前的城市的索引决定是否要换行,即新建一个LinearLayout。后来觉得这样实现不太好看,代码太乱了,于是就想到了用自定义View,原理跟原来的差不多,也是利用当前城市的索引决定是否换行。
直接上源码,
- package cn.hnsi.android.apps.smartlife.ui.widget;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.View;
- import android.view.ViewGroup;
- /**
- * 显示城市名称
- * @author LiChaofei
- * <br/>2014-3-24 下午3:03:21
- */
- public class CitiesLayout extends ViewGroup {
- private static final String TAG="CitiesLayout";
- private static final int COLUMN_COUNT=5;
- private static final int HORIZONTAL_SPACE=2;
- private static final int VERTICAL_SPACE=5;
- private int maxChildWidth=0;
- private int maxChildHeight=0;
- public CitiesLayout(Context context) {
- super(context);
- }
- public CitiesLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- // TODO Auto-generated constructor stub
- }
- public CitiesLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSize=MeasureSpec.getSize(widthMeasureSpec);
- int heightSize=MeasureSpec.getSize(heightMeasureSpec);
- int paddingLeft=this.getPaddingLeft();
- int paddingRight=this.getPaddingTop();
- int paddingTop=this.getPaddingTop();
- int paddingBottom=this.getPaddingBottom();
- // Log.d(TAG, "调用onMeasure,width="+widthSize+",height="+heightSize+",paddingLeft="+paddingLeft+",paddingRight="+paddingRight+",paddingTop="+paddingTop+",paddingBottom="+paddingBottom);
- //类似9宫格的形式
- maxChildHeight=maxChildWidth=(widthSize-paddingLeft-paddingRight)/COLUMN_COUNT-HORIZONTAL_SPACE*2;
- int childMeasureWidthSpec=MeasureSpec.makeMeasureSpec(maxChildWidth, MeasureSpec.EXACTLY);
- int childMeasureHeightSpec=MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY);
- int childCount = getChildCount();
- for (int index = 0; index < childCount; index++) {
- final View child = getChildAt(index);
- // measure
- child.measure(childMeasureWidthSpec, childMeasureHeightSpec);
- }
- int rowCount=childCount%COLUMN_COUNT==0?childCount/COLUMN_COUNT:childCount/COLUMN_COUNT+1;
- heightSize=(maxChildHeight+VERTICAL_SPACE*2)*rowCount+paddingTop+paddingBottom;
- heightMeasureSpec=MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
- setMeasuredDimension(
- resolveSize(widthSize, widthMeasureSpec),
- resolveSize(heightSize, heightMeasureSpec));
- }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // Log.d(TAG, "maxChildWidth="+maxChildWidth);
- int paddingLeft=this.getPaddingLeft();
- int paddingTop=this.getPaddingTop();
- int total=getChildCount();
- for(int i=0;i<total;i++){
- final View child=getChildAt(i);
- int row=i/COLUMN_COUNT;
- int colomn=i%COLUMN_COUNT;
- int left =paddingLeft+(maxChildWidth+HORIZONTAL_SPACE*2)*colomn+HORIZONTAL_SPACE;
- int top = paddingTop+(maxChildHeight+VERTICAL_SPACE*2)*row+VERTICAL_SPACE;
- // Log.d(TAG, "left="+left+",top="+top);
- child.layout(left, top, left+maxChildWidth, top+maxChildHeight);
- }
- }
- }
Adapter的源码
- protected class CityAdapter extends BaseAdapter {
- Context mContext;
- LayoutInflater inflater;
- List<ProvinceEntity> dataList;
- // int unitWidth;
- public CityAdapter(Context context, List<ProvinceEntity> datas) {
- mContext = context;
- inflater = (LayoutInflater) context
- .getSystemService(LAYOUT_INFLATER_SERVICE);
- dataList = datas;
- // DisplayMetrics metrics = new DisplayMetrics();
- // getWindowManager().getDefaultDisplay().getMetrics(metrics);
- // unitWidth=(metrics.widthPixels-5*6)/5;
- }
- @Override
- public int getCount() {
- return dataList != null ? dataList.size() : 0;
- }
- @Override
- public Object getItem(int position) {
- return dataList.get(position);
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- convertView = inflater.inflate(R.layout.list_item_city, parent,false);
- TextView provinceName = (TextView) convertView
- .findViewById(android.R.id.title);
- ProvinceEntity province = dataList.get(position);
- provinceName.setText(province.name);
- List<CityEntity> cities = province.cities;
- CitiesLayout container=(CitiesLayout) convertView.findViewById(R.id.city_container);
- for (int i = 0, len = cities.size(); i < len; i++) {
- CityEntity city=cities.get(i);
- TextView cityName=createTextView(city);
- container.addView(cityName);
- }
- return convertView;
- }
- /**
- * 创建一个TextView
- * @author LiChaofei
- * <br/>2013-12-10 下午2:48:59
- * @param city TODO
- * @return
- */
- private TextView createTextView(final CityEntity city) {
- final TextView view=new TextView(mContext);
- LayoutParams params=new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
- // params.leftMargin=2;
- // params.rightMargin=2;
- view.setLayoutParams(params);
- // view.setPadding(10, 10, 10, 10);
- view.setTextColor(Color.BLACK);
- view.setBackgroundResource(R.drawable.bg_city_selector);
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
- view.setGravity(Gravity.CENTER);
- view.setText(city.name);
- view.setTag(city.cityId);
- view.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- intent.putExtra(WeatherActivity.CITY_ID, city.cityId);
- intent.putExtra(WeatherActivity.CITY_NAME, city.name);
- setResult(RESULT_OK, intent);
- finish();
- }
- });
- return view;
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true">
- <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
- <item>
- <shape android:shape="rectangle" >
- <solid android:color="@color/black" />
- <corners android:radius="5dp" />
- <stroke
- android:width="1dip"
- android:color="@color/black" />
- </shape>
- </item>
- <item
- android:bottom="2px"
- android:left="0px"
- android:right="0px">
- <shape android:shape="rectangle" >
- <gradient
- android:angle="90"
- android:endColor="#cccccc"
- android:startColor="#e1e1e1" />
- <corners android:radius="5dp" />
- <stroke
- android:width="0dip"
- android:color="@color/black" />
- </shape>
- </item>
- </layer-list>
- </item>
- <!-- 普通状态 -->
- <item><layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item><shape android:shape="rectangle">
- <solid android:color="@color/black" />
- <corners android:radius="5dp" />
- <stroke android:width="1dip" android:color="@color/black" />
- </shape></item>
- <item android:bottom="2px" android:left="0px" android:right="0px"><shape android:shape="rectangle">
- <gradient android:angle="90" android:endColor="#e1e1e1" android:startColor="#cccccc" />
- <corners android:radius="5dp" />
- <stroke android:width="0dip" android:color="@color/black" />
- </shape></item>
- </layer-list></item>
- </selector>
代码比较简单,我就不多说了,如果有不对的地方,欢迎批评指正。