以前做的项目需要用到这样的一个界面,先发一张效果图,个人感觉还算可以,下面把我的实现过程记录一下。
首先,数据格式是这样的
很明显这个界面整体是一个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); } } }
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; } }用到的bg_city_selector
<?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>