Advertisement

Android开发--全国各城市列表并按首字母排序加快速定位

阅读量:

我们通常会在各种商业应用中面对城市选择的问题。一般来说,在选择城市时会按照字母顺序来排序。之前遇到过的类似问题今天又拿出来复习了一下。具体思路如下:

为了获取一个包含全国各城市的数据库方案或Json、Xml等多种格式的数据存储结构,在开始开发前我通过网络搜索发现了一个名为db的数据本地文件。这个本地数据结构存储了各个城市名称及其拼音首字母信息,并且位于工程目录下的res/raw目录中(该目录通常不会被Android编译系统处理)。在访问这些数据时优先检查此本地数据是否已存在(通常手机系统会将这类本地数据存放在data/data/packagename/databases目录下),如果未找到则手动复制至指定位置以确保正常运行流程中的完整性需求。完成上述操作后即可按照城市名称的首字母对这些数据进行排序和检索。

对于快速定位的实现:通过QuickLocationBar进行快速定位,在OnTouchLetterChangedListener中完成对ListView的快速定位

显示效果

代码如下:

CityActivity类:

复制代码
 package com.example.citytest;

    
  
    
 import java.util.ArrayList;
    
 import java.util.HashMap;
    
  
    
 import android.app.Activity;
    
 import android.database.Cursor;
    
 import android.database.sqlite.SQLiteDatabase;
    
 import android.os.Bundle;
    
 import android.view.View;
    
 import android.widget.AdapterView;
    
 import android.widget.AdapterView.OnItemClickListener;
    
 import android.widget.ListView;
    
 import android.widget.TextView;
    
 import android.widget.Toast;
    
  
    
 import com.example.citytest.widget.QuicLocationBar;
    
 import com.example.citytest.widget.QuicLocationBar.OnTouchLetterChangedListener;
    
  
    
 public class CityActivity extends Activity {
    
  
    
 	private ListView mCityLit;
    
 	private TextView overlay;
    
 	private QuicLocationBar mQuicLocationBar;
    
 	private HashMap<String, Integer> alphaIndexer;
    
 	private ArrayList<CityBean> mCityNames;
    
  
    
 	@Override
    
 	public void onCreate(Bundle savedInstanceState) {
    
 		// TODO Auto-generated method stub
    
 		super.onCreate(savedInstanceState);
    
 		setContentView(R.layout.activity_city);
    
  
    
 		mQuicLocationBar = (QuicLocationBar) findViewById(R.id.city_loactionbar);
    
 		mQuicLocationBar
    
 				.setOnTouchLitterChangedListener(new LetterListViewListener());
    
 		overlay = (TextView) findViewById(R.id.city_dialog);
    
 		mCityLit = (ListView) findViewById(R.id.city_list);
    
 		mQuicLocationBar.setTextDialog(overlay);
    
 		initList();
    
 	}
    
  
    
 	private void initList() {
    
 		mCityNames = getCityNames();
    
 		CityAdapter adapter = new CityAdapter(CityActivity.this, mCityNames);
    
 		mCityLit.setAdapter(adapter);
    
 		alphaIndexer = adapter.getCityMap();
    
 		mCityLit.setOnItemClickListener(new CityListOnItemClick());
    
 	}
    
  
    
 	private ArrayList<CityBean> getCityNames() {
    
 		CityDBManager dbManager = new CityDBManager(CityActivity.this);
    
 		dbManager.openDateBase();
    
 		dbManager.closeDatabase();
    
 		SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(CityDBManager.DB_PATH
    
 				+ "/" + CityDBManager.DB_NAME, null);
    
 		ArrayList<CityBean> names = new ArrayList<CityBean>();
    
 		Cursor cursor = database.rawQuery(
    
 				"SELECT * FROM T_City ORDER BY NameSort", null);
    
 		if (cursor.moveToFirst()) {
    
 			do {
    
 				CityBean cityModel = new CityBean();
    
 				cityModel.setCityName(cursor.getString(cursor
    
 						.getColumnIndex("CityName")));
    
 				cityModel.setNameSort(cursor.getString(cursor
    
 						.getColumnIndex("NameSort")));
    
 				names.add(cityModel);
    
 			} while (cursor.moveToNext());
    
 		}
    
 		database.close();
    
 		return names;
    
 	}
    
  
    
 	private class CityListOnItemClick implements OnItemClickListener {
    
  
    
 		@Override
    
 		public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
    
 				long arg3) {
    
 			CityBean cityModel = (CityBean) mCityLit.getAdapter()
    
 					.getItem(pos);
    
 			Toast.makeText(CityActivity.this, cityModel.getCityName(),
    
 					Toast.LENGTH_SHORT).show();
    
 		}
    
  
    
 	}
    
  
    
 	private class LetterListViewListener implements
    
 			OnTouchLetterChangedListener {
    
  
    
 		@Override
    
 		public void touchLetterChanged(String s) {
    
 			// TODO Auto-generated method stub
    
 			if (alphaIndexer.get(s) != null) {
    
 				int position = alphaIndexer.get(s);
    
 				mCityLit.setSelection(position);
    
 			}
    
 		}
    
  
    
 	}
    
  
    
 }

Activity的布局文件:

复制代码
 <?xml version="1.0" encoding="utf-8"?>

    
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    
     android:layout_width="match_parent"
    
     android:layout_height="match_parent" >
    
  
    
     <LinearLayout
    
     android:layout_width="fill_parent"
    
     android:layout_height="fill_parent"
    
     android:layout_gravity="center"
    
     android:orientation="vertical" >
    
  
    
     <ListView
    
         android:id="@+id/city_list"
    
         android:layout_width="match_parent"
    
         android:layout_height="match_parent"
    
         android:layout_gravity="center"
    
         android:divider="@color/lightgray"
    
         android:dividerHeight="2dp" />
    
     </LinearLayout>
    
  
    
     <TextView
    
     android:id="@+id/city_dialog"
    
     android:layout_width="80.0dip"
    
     android:layout_height="80.0dip"
    
     android:layout_gravity="center"
    
     android:gravity="center"
    
     android:textColor="@color/myblack"
    
     android:textSize="30.0sp"
    
     android:visibility="gone" />
    
  
    
     <com.example.citytest.widget.QuicLocationBar
    
     android:id="@+id/city_loactionbar"
    
     android:layout_width="30.0dip"
    
     android:layout_height="fill_parent"
    
     android:layout_gravity="right|center"
    
     android:paddingBottom="2dp" />
    
  
    
 </FrameLayout>

CityAdapter类,ListView适配

复制代码
 package com.example.citytest;

    
  
    
 import java.util.HashMap;
    
 import java.util.List;
    
  
    
 import android.content.Context;
    
 import android.view.LayoutInflater;
    
 import android.view.View;
    
 import android.view.ViewGroup;
    
 import android.widget.BaseAdapter;
    
 import android.widget.TextView;
    
  
    
 /** * ListView适配
    
  * 提供一个方法来获得 保存首字母和该首字母城市的第一个出现的位置HashMap
    
  * 通过记录前一个首字母与当前首字母是否相同,如果不同加入HashMap中同时显示该字母
    
  * @author acer
    
  * */
    
 public class CityAdapter extends BaseAdapter {
    
 	private LayoutInflater inflater;
    
 	private List<CityBean> list;
    
 	private HashMap<String, Integer> alphaIndexer;
    
 	private String[] sections;
    
  
    
 	public CityAdapter(Context context, List<CityBean> list) {
    
  
    
 		this.inflater = LayoutInflater.from(context);
    
 		this.list = list;
    
 		alphaIndexer = new HashMap<String, Integer>();
    
 		sections = new String[list.size()];
    
  
    
 		for (int i = 0; i < list.size(); i++) {
    
 			String currentStr = list.get(i).getNameSort();
    
 			String previewStr = (i - 1) >= 0 ? list.get(i - 1).getNameSort()
    
 					: " ";
    
 			if (!previewStr.equals(currentStr)) {//前一个首字母与当前首字母不同时加入HashMap中同时显示该字母
    
 				String name = list.get(i).getNameSort();
    
 				alphaIndexer.put(name, i);
    
 				sections[i] = name;
    
 			}
    
 		}
    
  
    
 	}
    
  
    
 	public HashMap<String, Integer> getCityMap(){
    
 		return alphaIndexer;
    
 	}
    
 	
    
 	@Override
    
 	public int getCount() {
    
 		return list.size();
    
 	}
    
  
    
 	@Override
    
 	public Object getItem(int position) {
    
 		return list.get(position);
    
 	}
    
  
    
 	@Override
    
 	public long getItemId(int position) {
    
 		return position;
    
 	}
    
  
    
 	@Override
    
 	public View getView(int position, View convertView, ViewGroup parent) {
    
 		ViewHolder holder;
    
 		if (convertView == null) {
    
 			convertView = inflater.inflate(R.layout.item_city, null);
    
 			holder = new ViewHolder();
    
 			holder.alpha = (TextView) convertView
    
 					.findViewById(R.id.item_city_alpha);
    
 			holder.name = (TextView) convertView
    
 					.findViewById(R.id.item_city_name);
    
 			convertView.setTag(holder);
    
 		} else {
    
 			holder = (ViewHolder) convertView.getTag();
    
 		}
    
  
    
 		holder.name.setText(list.get(position).getCityName());
    
 		String currentStr = list.get(position).getNameSort();
    
 		String previewStr = (position - 1) >= 0 ? list.get(position - 1)
    
 				.getNameSort() : " ";
    
 		if (!previewStr.equals(currentStr)) {
    
 			holder.alpha.setVisibility(View.VISIBLE);
    
 			holder.alpha.setText(currentStr);
    
 		} else {
    
 			holder.alpha.setVisibility(View.GONE);
    
 		}
    
 		return convertView;
    
 	}
    
  
    
 	private class ViewHolder {
    
 		TextView alpha;
    
 		TextView name;
    
 	}
    
  
    
 }

CityBean类:

复制代码
 package com.example.citytest;

    
  
    
 /** * 记录每一个城市的中文名称及首字母
    
  * @author acer
    
  * */
    
 public class CityBean {
    
 	private String name;
    
 	private String firstAlpha;
    
  
    
 	public String getCityName() {
    
 		return name;
    
 	}
    
  
    
 	public void setCityName(String cityName) {
    
 		name = cityName;
    
 	}
    
  
    
 	public String getNameSort() {
    
 		return firstAlpha;
    
 	}
    
  
    
 	public void setNameSort(String nameSort) {
    
 		firstAlpha = nameSort;
    
 	}
    
  
    
 }

ListView中Item显示的布局文件

复制代码
 <?xml version="1.0" encoding="utf-8"?>

    
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    
     android:layout_width="match_parent"
    
     android:layout_height="match_parent" >
    
  
    
     <TextView
    
     android:id="@+id/item_city_alpha"
    
     android:layout_width="fill_parent"
    
     android:layout_height="25dp"
    
     android:background="@color/darkgray"
    
     android:paddingLeft="13dip"
    
     android:textAppearance="?android:textAppearanceMedium"
    
     android:textColor="@color/myred" />
    
  
    
     <TextView
    
     android:id="@+id/item_city_name"
    
     android:layout_width="wrap_content"
    
     android:layout_height="35dp"
    
     android:layout_below="@id/item_city_alpha"
    
     android:layout_margin="15.0dip"
    
     android:singleLine="true"
    
     android:text="name"
    
     android:textAppearance="?android:textAppearanceMedium"
    
     android:textColor="#212121" />
    
  
    
 </RelativeLayout>

CityDBManager数据库管理类

复制代码
 package com.example.citytest;

    
  
    
 import java.io.File;
    
 import java.io.FileNotFoundException;
    
 import java.io.FileOutputStream;
    
 import java.io.IOException;
    
 import java.io.InputStream;
    
  
    
 import android.content.Context;
    
 import android.database.sqlite.SQLiteDatabase;
    
 import android.os.Environment;
    
  
    
 /** * 数据库管理类
    
  * 访问数据库时首先检查该数据库文件是否存在,如果不存在进行拷贝操作
    
  * @author acer
    
  * */
    
 public class CityDBManager {
    
 	private final int BUFFER_SIZE = 10240;
    
 	private static final String PACKAGE_NAME = "com.example.citytest";
    
 	public static final String DB_NAME = "china_city_name.db";
    
 	public static final String DB_PATH = "/data"
    
 			+ Environment.getDataDirectory().getAbsolutePath() + "/"
    
 			+ PACKAGE_NAME + "/databases"; 
    
 	private Context mContext;
    
 	private SQLiteDatabase database;
    
  
    
 	public CityDBManager(Context context) {
    
 		this.mContext = context;
    
 	}
    
  
    
 	public void openDateBase() {
    
 		this.database = this.openDateBase(DB_PATH + "/" + DB_NAME );
    
  
    
 	}
    
  
    
 	private SQLiteDatabase openDateBase(String dbFile) {
    
 		File file = new File(dbFile);
    
 		if (!file.exists()) {
    
 			File folder = new File(DB_PATH);
    
 			if (!folder.exists()) {
    
 				folder.mkdir();
    
 			}
    
 			InputStream stream = mContext.getResources().openRawResource(
    
 					R.raw.china_city_name);
    
 			try {
    
 				FileOutputStream outputStream = new FileOutputStream(dbFile);
    
 				byte[] buffer = new byte[BUFFER_SIZE];
    
 				int count = 0;
    
 				while ((count = stream.read(buffer)) > 0) {
    
 					outputStream.write(buffer, 0, count);
    
 				}
    
 				outputStream.close();
    
 				stream.close();
    
 				SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile,
    
 						null);
    
 				return db;
    
 			} catch (FileNotFoundException e) {
    
 				// TODO Auto-generated catch block
    
 				e.printStackTrace();
    
 			} catch (IOException e) {
    
 				// TODO Auto-generated catch block
    
 				e.printStackTrace();
    
 			}
    
 		}
    
 		return database;
    
 	}
    
  
    
 	public void closeDatabase() {
    
 		if (database != null && database.isOpen()) {
    
 			this.database.close();
    
 		}
    
 	}
    
 }

QuickLocationBar快速定位侧边栏

复制代码
 package com.example.citytest.widget;

    
  
    
 import android.content.Context;
    
 import android.graphics.Canvas;
    
 import android.graphics.Paint;
    
 import android.graphics.Typeface;
    
 import android.util.AttributeSet;
    
 import android.view.MotionEvent;
    
 import android.view.View;
    
 import android.widget.TextView;
    
  
    
 import com.example.citytest.R;
    
  
    
 /** * 快速定位侧边栏
    
  * 在OnTouchLetterChangedListener中对点击当前的字母做处理
    
  * 需要设置一个TextView来显示当前点击的字母
    
  * @author acer
    
  * */
    
 public class QuicLocationBar extends View {
    
  
    
 	private String characters[] = { "#", "A", "B", "C", "D", "E", "F", "G",
    
 			"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
    
 			"U", "V", "W", "X", "Y", "Z" };
    
 	private int choose = -1;
    
 	private Paint paint = new Paint();
    
 	private OnTouchLetterChangedListener mOnTouchLetterChangedListener;
    
 	private TextView mTextDialog;
    
  
    
 	public QuicLocationBar(Context context, AttributeSet attrs, int defStyleAttr) {
    
 		super(context, attrs, defStyleAttr);
    
 		// TODO Auto-generated constructor stub
    
 	}
    
  
    
 	public QuicLocationBar(Context context, AttributeSet attrs) {
    
 		super(context, attrs);
    
 		// TODO Auto-generated constructor stub
    
 	}
    
  
    
 	public QuicLocationBar(Context context) {
    
 		super(context);
    
 		// TODO Auto-generated constructor stub
    
 	}
    
  
    
 	public void setOnTouchLitterChangedListener(
    
 			OnTouchLetterChangedListener onTouchLetterChangedListener) {
    
 		this.mOnTouchLetterChangedListener = onTouchLetterChangedListener;
    
 	}
    
  
    
 	public void setTextDialog(TextView dialog) {
    
 		this.mTextDialog = dialog;
    
 	}
    
  
    
 	@Override
    
 	protected void onDraw(Canvas canvas) {
    
 		// TODO Auto-generated method stub
    
 		super.onDraw(canvas);
    
 		int width = getWidth();
    
 		int height = getHeight();
    
 		int singleHeight = height / characters.length;
    
 		for (int i = 0; i < characters.length; i++) {
    
 			// 对paint进行相关的参数设置
    
 			paint.setColor(getResources().getColor(R.color.myblack));
    
 			paint.setTypeface(Typeface.DEFAULT_BOLD);
    
 			paint.setAntiAlias(true);
    
 			paint.setTextSize(150*(float) width/320);
    
 			if (i == choose) {// choose变量表示当前显示的字符位置,若没有触摸则为-1
    
 				paint.setColor(getResources().getColor(R.color.myred));
    
 				paint.setFakeBoldText(true);
    
 			}
    
 			// 计算字符的绘制的位置
    
 			float xPos = width / 2 - paint.measureText(characters[i]) / 2;
    
 			float yPos = singleHeight * i + singleHeight;
    
 			// 在画布上绘制字符
    
 			canvas.drawText(characters[i], xPos, yPos, paint);
    
 			paint.reset();// 每次绘制完成后不要忘记重制Paint
    
 		}
    
 	}
    
  
    
 	
    
 	
    
 	@Override
    
 	public boolean dispatchTouchEvent(MotionEvent event) {
    
 		int action = event.getAction();
    
 		float y = event.getY();
    
 		int c = (int) (y / getHeight() * characters.length);
    
  
    
 		switch (action) {
    
 		case MotionEvent.ACTION_UP:
    
 			choose = -1;//
    
 			setBackgroundColor(0x0000);
    
 			invalidate();
    
 			if (mTextDialog != null) {
    
 				mTextDialog.setVisibility(View.GONE);
    
 			}
    
 			break;
    
  
    
 		case MotionEvent.ACTION_DOWN:
    
 		case MotionEvent.ACTION_MOVE:
    
 			setBackgroundColor(getResources().getColor(R.color.darkgray));
    
 			if (choose != c) {
    
 				if (c >= 0 && c < characters.length) {
    
 					if (mOnTouchLetterChangedListener != null) {
    
 						mOnTouchLetterChangedListener
    
 								.touchLetterChanged(characters[c]);
    
 					}
    
 					if (mTextDialog != null) {
    
 						mTextDialog.setText(characters[c]);
    
 						mTextDialog.setVisibility(View.VISIBLE);
    
 					}
    
 					choose = c;
    
 					invalidate();
    
 				}
    
 			}
    
 			break;
    
 		}
    
 		return true;
    
 	}
    
  
    
 	public interface OnTouchLetterChangedListener {
    
 		public void touchLetterChanged(String s);
    
 	}
    
  
    
 }

全部评论 (0)

还没有任何评论哟~