android自定义布局——城市选择界面
2016-08-08 23:04
579 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。
以前做的项目需要用到这样的一个界面,先发一张效果图,个人感觉还算可以,下面把我的实现过程记录一下。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/25/41f10ab2f83f7e8f34c3ab5cfd5665a2)
首先,数据格式是这样的
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/25/eaa457a0b1805e60ed4b37a0122861d8)
很明显这个界面整体是一个listview,每个省是一个listitem,刚开始实现方法是在adapter的getview里动态的在每个listitem里添加LinearLayout,每一行城市就是一个LinearLayout,通过判断当前的城市的索引决定是否要换行,即新建一个LinearLayout。后来觉得这样实现不太好看,代码太乱了,于是就想到了用自定义View,原理跟原来的差不多,也是利用当前城市的索引决定是否换行。
直接上源码,
[java] view
plain copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
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的源码
[java] view
plain copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
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
[html] view
plain copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
<?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>
代码比较简单,我就不多说了,如果有不对的地方,欢迎批评指正。
以前做的项目需要用到这样的一个界面,先发一张效果图,个人感觉还算可以,下面把我的实现过程记录一下。
首先,数据格式是这样的
很明显这个界面整体是一个listview,每个省是一个listitem,刚开始实现方法是在adapter的getview里动态的在每个listitem里添加LinearLayout,每一行城市就是一个LinearLayout,通过判断当前的城市的索引决定是否要换行,即新建一个LinearLayout。后来觉得这样实现不太好看,代码太乱了,于是就想到了用自定义View,原理跟原来的差不多,也是利用当前城市的索引决定是否换行。
直接上源码,
[java] view
plain copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
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的源码
[java] view
plain copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
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
[html] view
plain copy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
<?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>
代码比较简单,我就不多说了,如果有不对的地方,欢迎批评指正。
相关文章推荐
- 从源码安装Mysql/Percona 5.5
- 完美实现Android ListView中的TextView的跑马灯效果
- Android布局的小窍门?
- Web布局连载——两栏固定布局(五)
- android上改变listView的选中颜色
- PostgreSQL教程(八):索引详解
- Oracle外键不加索引引起死锁示例
- oracle 索引的相关介绍(创建、简介、技巧、怎样查看) .
- Delphi7中Listview的常用功能汇总
- Delphi控件ListView的属性及使用方法详解
- 样式表CSS布局经验
- 在winform下实现左右布局多窗口界面的方法之续篇
- 浅析Ruby的源代码布局及其编程风格
- 用SQL建立索引的方法步骤
- SQL2005重新生成索引的的存储过程 sp_rebuild
- SQL效率提升之一些SQL编写建议并有效利用索引
- SQLSERVER的非聚集索引结构深度理解
- SQL Server误区30日谈 第8天 有关对索引进行在线操作的误区
- SQL Server 索引介绍
- SqlServer 索引自动优化工具