package com.droid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.droid.MyLetterListView.OnTouchingLetterChangedListener;
public class Activity01 extends Activity implements OnScrollListener {
private BaseAdapter adapter;
private ResultListAdapter resultListAdapter;
private ListView personList;
private ListView resultList;//搜索结果列表
private TextView overlay; // 对话框首字母textview
private MyLetterListView letterListView; // A-Z listview
private HashMap alphaIndexer;// 存放存在的汉语拼音首字母和与之对应的列表位置
private String[] sections;// 存放存在的汉语拼音首字母
private Handler handler;
private OverlayThread overlayThread; // 显示首字母对话框
private ArrayList allCity_lists; // 所有城市列表
private ArrayList city_lists;// 城市列表
private ArrayList city_hot;//热门城市列表
private ArrayList city_result;//城市结果
private ArrayList city_history;//历史城市结果
private EditText sh; //搜索框
private TextView tv_noresult; //显示搜索结果
//定位
private LocationClient mLocationClient;
private MyLocationListener mMyLocationListener;
public TextView city;
private String currentCity; // 用于保存定位到的城市
private int locateProcess = 1; // 记录当前定位的状态 正在定位(1)-定位成功(2)-定位失败(3)
//是否需要新的
private boolean isNeedFresh;
//我们从文件的全国城市列表
private DatabaseHelper helper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
personList = (ListView) findViewById(R.id.list_view);
allCity_lists = new ArrayList();
city_hot = new ArrayList();
city_result = new ArrayList();
city_history = new ArrayList();
resultList = (ListView) findViewById(R.id.search_result);
sh = (EditText) findViewById(R.id.sh);
//没有该城市的搜索结果出现该提示消息
tv_noresult = (TextView) findViewById(R.id.tv_noresult);
helper = new DatabaseHelper(this);
//城市搜索框增加监听器
sh.addTextChangedListener(new TextWatcher() {
@Override
//文本改变前调用的方法
//这个方法被调用,说明在s字符串中,从start位置开始的count个字符即将被长度为after的新文本所取代。在这个方法里面改变s,会报错。
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if (s.toString() == null || "".equals(s.toString())) {
//View缺省(默认)为可见的,在应用可以通过setVisibility 修改View的可见性,View可用性可以有如下三种状态:
//View.VISIBLE View可见
//View.INVISIBLE View不可以见,但仍然占据可见时的大小和位置。
//View.GONE View不可见,且不占据空间
letterListView.setVisibility(View.VISIBLE);
personList.setVisibility(View.VISIBLE);
resultList.setVisibility(View.GONE);
tv_noresult.setVisibility(View.GONE);
} else {
//保证下一次进来搜索页面,不会保留上一次的搜索结果
city_result.clear();
letterListView.setVisibility(View.GONE);
personList.setVisibility(View.GONE);
getResultCityList(s.toString());
if (city_result.size() <= 0) {
tv_noresult.setVisibility(View.VISIBLE);
resultList.setVisibility(View.GONE);
} else {
tv_noresult.setVisibility(View.GONE);
resultList.setVisibility(View.VISIBLE);
resultListAdapter.notifyDataSetChanged();
}
}
}
@Override
//文本调用时的方法
// //这个方法被调用,说明在s字符串中,从start位置开始的count个字符刚刚取代了长度为before的旧文本。在这个方法里面改变
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
//方放调用完成后的方法
//这个方法被调用,那么说明s字符串的某个地方已经被改变。
public void afterTextChanged(Editable s) {
}
});
letterListView = (MyLetterListView) findViewById(R.id.MyLetterListView01);
letterListView
.setOnTouchingLetterChangedListener(new LetterListViewListener());
//字母表的角标,t
alphaIndexer = new HashMap();
handler = new Handler();
overlayThread = new OverlayThread();
isNeedFresh = true;
//城市列表的item点击事件
personList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
if (position >= 4) {
Toast.makeText(getApplicationContext(),
allCity_lists.get(position).getName(),
Toast.LENGTH_SHORT).show();
}
}
});
locateProcess = 1;
personList.setAdapter(adapter);
personList.setOnScrollListener(this);
resultListAdapter = new ResultListAdapter(this, city_result);
resultList.setAdapter(resultListAdapter);
resultList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
city_result.get(position).getName(), Toast.LENGTH_SHORT)
.show();
}
});
//首字母索引的方法
initOverlay();
//初始化城市
cityInit();
//初始化热门城市
hotCityInit();
//初始化曾经搜索过的城市
hisCityInit();
setAdapter(allCity_lists, city_hot, city_history);
mLocationClient = new LocationClient(this.getApplicationContext());
mMyLocationListener = new MyLocationListener();
mLocationClient.registerLocationListener(mMyLocationListener);
//对定位进行初始化
InitLocation();
//开始定位
mLocationClient.start();
}
//对城市信息进行插入操作
public void InsertCity(String name) {
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from recentcity where name = '"
+ name + "'", null);
if (cursor.getCount() > 0) { //
db.delete("recentcity", "name = ?", new String[] { name });
}
db.execSQL("insert into recentcity(name, date) values('" + name + "', "
+ System.currentTimeMillis() + ")");
db.close();
}
private void InitLocation() {
// 设置定位参数
LocationClientOption option = new LocationClientOption();
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(10000); // 10分钟扫描1次
// 需要地址信息,设置为其他任何值(string类型,且不能为null)时,都表示无地址信息。
option.setAddrType("all");
// 设置是否返回POI的电话和地址等详细信息。默认值为false,即不返回POI的电话和地址信息。
option.setPoiExtraInfo(true);
// 设置产品线名称。强烈建议您使用自定义的产品线名称,方便我们以后为您提供更高效准确的定位服务。
option.setProdName("通过GPS定位我当前的位置");
// 禁用启用缓存定位数据
option.disableCache(true);
// 设置最多可返回的POI个数,默认值为3。由于POI查询比较耗费流量,设置最多返回的POI个数,以便节省流量。
option.setPoiNumber(3);
// 设置定位方式的优先级。
// 当gps可用,而且获取了定位结果时,不再发起网络请求,直接返回给用户坐标。这个选项适合希望得到准确坐标位置的用户。如果gps不可用,再发起网络请求,进行定位。
option.setPriority(LocationClientOption.GpsFirst);
mLocationClient.setLocOption(option);
}
//城市信息的初始化处
private void cityInit() {
City city = new City("定位", "0"); // 当前定位城市
allCity_lists.add(city);
city = new City("最近", "1"); // 最近访问的城市
allCity_lists.add(city);
city = new City("热门", "2"); // 热门城市
allCity_lists.add(city);
city = new City("全部", "3"); // 全部城市
allCity_lists.add(city);
city_lists = getCityList();
allCity_lists.addAll(city_lists);
}
/**
* 热门城市
*/
//city方法中参数的"2"应该是设置在拼音检索中的优先级
//可以在这方法中自己添加热门城市的信息
public void hotCityInit() {
City city = new City("上海", "2");
city_hot.add(city);
city = new City("北京", "2");
city_hot.add(city);
city = new City("广州", "2");
city_hot.add(city);
city = new City("深圳", "2");
city_hot.add(city);
city = new City("武汉", "2");
city_hot.add(city);
city = new City("天津", "2");
city_hot.add(city);
city = new City("西安", "2");
city_hot.add(city);
city = new City("南京", "2");
city_hot.add(city);
city = new City("杭州", "2");
city_hot.add(city);
city = new City("成都", "2");
city_hot.add(city);
city = new City("重庆", "2");
city_hot.add(city);
city = new City("吉安", "2");
city_hot.add(city);
}
private void hisCityInit() {
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.rawQuery(
"select * from recentcity order by date desc limit 0, 3", null);
while (cursor.moveToNext()) {
city_history.add(cursor.getString(1));
}
cursor.close();
db.close();
}
@SuppressWarnings("unchecked")
private ArrayList getCityList() {
DBHelper dbHelper = new DBHelper(this);
ArrayList list = new ArrayList();
try {
dbHelper.createDataBase();
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from city", null);
City city;
while (cursor.moveToNext()) {
city = new City(cursor.getString(1), cursor.getString(2));
list.add(city);
}
cursor.close();
db.close();
} catch (IOException e) {
e.printStackTrace();
}
Collections.sort(list, comparator);
return list;
}
@SuppressWarnings("unchecked")
private void getResultCityList(String keyword) {
DBHelper dbHelper = new DBHelper(this);
try {
dbHelper.createDataBase();
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery(
"select * from city where name like \"%" + keyword
+ "%\" or pinyin like \"%" + keyword + "%\"", null);
City city;
Log.e("info", "length = " + cursor.getCount());
while (cursor.moveToNext()) {
city = new City(cursor.getString(1), cursor.getString(2));
city_result.add(city);
}
cursor.close();
db.close();
} catch (IOException e) {
e.printStackTrace();
}
Collections.sort(city_result, comparator);
}
/**
* a-z排序
*/
@SuppressWarnings("rawtypes")
Comparator comparator = new Comparator() {
@Override
public int compare(City lhs, City rhs) {
String a = lhs.getPinyi().substring(0, 1);
String b = rhs.getPinyi().substring(0, 1);
int flag = a.compareTo(b);
if (flag == 0) {
return a.compareTo(b);
} else {
return flag;
}
}
};
private void setAdapter(List list, List hotList,
List hisCity) {
adapter = new ListAdapter(this, list, hotList, hisCity);
personList.setAdapter(adapter);
}
/**
* 实现实位回调监听
*/
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation arg0) {
Log.e("info", "city = " + arg0.getCity());
if (!isNeedFresh) {
return;
}
isNeedFresh = false;
if (arg0.getCity() == null) {
locateProcess = 3; // 定位失败
personList.setAdapter(adapter);
adapter.notifyDataSetChanged();
return;
}
currentCity = arg0.getCity().substring(0,
arg0.getCity().length() - 1);
locateProcess = 2; // 定位成功
personList.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
@Override
public void onReceivePoi(BDLocation arg0) {
}
}
private class ResultListAdapter extends BaseAdapter {
private LayoutInflater inflater;
private ArrayList results = new ArrayList();
public ResultListAdapter(Context context, ArrayList results) {
inflater = LayoutInflater.from(context);
this.results = results;
}
@Override
public int getCount() {
return results.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
viewHolder = new ViewHolder();
viewHolder.name = (TextView) convertView
.findViewById(R.id.name);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.name.setText(results.get(position).getName());
return convertView;
}
class ViewHolder {
TextView name;
}
}
public class ListAdapter extends BaseAdapter {
private Context context;
private LayoutInflater inflater;
private List list;
private List hotList;
private List hisCity;
final int VIEW_TYPE = 5;
public ListAdapter(Context context, List list,
List hotList, List hisCity) {
this.inflater = LayoutInflater.from(context);
this.list = list;
this.context = context;
this.hotList = hotList;
this.hisCity = hisCity;
alphaIndexer = new HashMap();
sections = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
// 当前汉语拼音首字母
String currentStr = getAlpha(list.get(i).getPinyi());
// 上一个汉语拼音首字母,如果不存在为" "
String previewStr = (i - 1) >= 0 ? getAlpha(list.get(i - 1)
.getPinyi()) : " ";
if (!previewStr.equals(currentStr)) {
String name = getAlpha(list.get(i).getPinyi());
alphaIndexer.put(name, i);
sections[i] = name;
}
}
}
@Override
public int getViewTypeCount() {
return VIEW_TYPE;
}
@Override
public int getItemViewType(int position) {
return position < 4 ? position : 4;
}
@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;
}
ViewHolder holder;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int viewType = getItemViewType(position);
if (viewType == 0) { // 定位
convertView = inflater.inflate(R.layout.frist_list_item, null);
//定位的信息/提示
TextView locateHint = (TextView) convertView
.findViewById(R.id.locateHint);
//定位城市的信息,例如你在广州,这个textView显示的就是广州
city = (TextView) convertView.findViewById(R.id.lng_city);
city.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//如果定位成功的话
if (locateProcess == 2) {
Toast.makeText(getApplicationContext(),
city.getText().toString(),
Toast.LENGTH_SHORT).show();
}
//如果定位失败的话,我们把定位状态在切换到正在定位
//一般我们出现的定位失败的情况都是未开启网络或者wifl或者gps
else if (locateProcess == 3) {
locateProcess = 1;
personList.setAdapter(adapter);
//刷新我们列表
adapter.notifyDataSetChanged();
mLocationClient.stop();
//刷新为新的
isNeedFresh = true;
InitLocation();
//当我们的定位城市信息列表为空的时候,我们继续开启定位
currentCity = "";
mLocationClient.start();
}
}
});
//我们定位中等待的icon图标
ProgressBar pbLocate = (ProgressBar) convertView
.findViewById(R.id.pbLocate);
if (locateProcess == 1) { // 正在定位
locateHint.setText("正在定位");
city.setVisibility(View.GONE);
pbLocate.setVisibility(View.VISIBLE);
} else if (locateProcess == 2) { // 定位成功
locateHint.setText("当前定位城市");
city.setVisibility(View.VISIBLE);
city.setText(currentCity);
mLocationClient.stop();
pbLocate.setVisibility(View.GONE);
} else if (locateProcess == 3) {
locateHint.setText("未定位到城市,请选择");
city.setVisibility(View.VISIBLE);
city.setText("重新选择");
pbLocate.setVisibility(View.GONE);
}
} else if (viewType == 1) { // 最近访问城市
convertView = inflater.inflate(R.layout.recent_city, null);
GridView rencentCity = (GridView) convertView
.findViewById(R.id.recent_city);
rencentCity
.setAdapter(new HitCityAdapter(context, this.hisCity));
rencentCity.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
city_history.get(position), Toast.LENGTH_SHORT)
.show();
}
});
TextView recentHint = (TextView) convertView
.findViewById(R.id.recentHint);
recentHint.setText("最近访问的城市");
} else if (viewType == 2) {
convertView = inflater.inflate(R.layout.recent_city, null);
GridView hotCity = (GridView) convertView
.findViewById(R.id.recent_city);
hotCity.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
city_hot.get(position).getName(),
Toast.LENGTH_SHORT).show();
}
});
hotCity.setAdapter(new HotCityAdapter(context, this.hotList));
TextView hotHint = (TextView) convertView
.findViewById(R.id.recentHint);
hotHint.setText("热门城市");
} else if (viewType == 3) {
convertView = inflater.inflate(R.layout.total_item, null);
} else {
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.alpha = (TextView) convertView
.findViewById(R.id.alpha);
holder.name = (TextView) convertView
.findViewById(R.id.name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (position >= 1) {
holder.name.setText(list.get(position).getName());
String currentStr = getAlpha(list.get(position).getPinyi());
String previewStr = (position - 1) >= 0 ? getAlpha(list
.get(position - 1).getPinyi()) : " ";
if (!previewStr.equals(currentStr)) {
holder.alpha.setVisibility(View.VISIBLE);
//这里是设置首字母的 比如 重庆 C首字母
holder.alpha.setText(currentStr);
} else {
holder.alpha.setVisibility(View.GONE);
}
}
}
return convertView;
}
private class ViewHolder {
TextView alpha; // 首字母标题
TextView name; // 城市名字
}
}
@Override
//封装着定位停止的方法
protected void onStop() {
mLocationClient.stop();
super.onStop();
}
class HotCityAdapter extends BaseAdapter {
private Context context;
private LayoutInflater inflater;
private List hotCitys;
public HotCityAdapter(Context context, List hotCitys) {
this.context = context;
inflater = LayoutInflater.from(this.context);
this.hotCitys = hotCitys;
}
@Override
public int getCount() {
return hotCitys.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = inflater.inflate(R.layout.item_city, null);
TextView city = (TextView) convertView.findViewById(R.id.city);
city.setText(hotCitys.get(position).getName());
return convertView;
}
}
class HitCityAdapter extends BaseAdapter {
private Context context;
private LayoutInflater inflater;
private List hotCitys;
public HitCityAdapter(Context context, List hotCitys) {
this.context = context;
inflater = LayoutInflater.from(this.context);
this.hotCitys = hotCitys;
}
@Override
public int getCount() {
return hotCitys.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = inflater.inflate(R.layout.item_city, null);
TextView city = (TextView) convertView.findViewById(R.id.city);
city.setText(hotCitys.get(position));
return convertView;
}
}
private boolean mReady;
// 初始化汉语拼音首字母弹出提示框
private void initOverlay() {
mReady = true;
LayoutInflater inflater = LayoutInflater.from(this);
overlay = (TextView) inflater.inflate(R.layout.overlay, null);
overlay.setVisibility(View.INVISIBLE);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
WindowManager windowManager = (WindowManager) this
.getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(overlay, lp);
}
private boolean isScroll = false;
private class LetterListViewListener implements
OnTouchingLetterChangedListener {
@Override
//overlay覆盖物
public void onTouchingLetterChanged(final String s) {
isScroll = false;
if (alphaIndexer.get(s) != null) {
int position = alphaIndexer.get(s);
personList.setSelection(position);
overlay.setText(s);
overlay.setVisibility(View.VISIBLE);
handler.removeCallbacks(overlayThread);
// 延迟一秒后执行,让overlay为不可见
handler.postDelayed(overlayThread, 1000);
}
}
}
// 设置overlay不可见
private class OverlayThread implements Runnable {
@Override
public void run() {
overlay.setVisibility(View.GONE);
}
}
// 获得汉语拼音首字母
private String getAlpha(String str) {
if (str == null) {
return "#";
}
if (str.trim().length() == 0) {
return "#";
}
char c = str.trim().substring(0, 1).charAt(0);
// 正则表达式,判断首字母是否是英文字母
Pattern pattern = Pattern.compile("^[A-Za-z]+$");
if (pattern.matcher(c + "").matches()) {
return (c + "").toUpperCase();
} else if (str.equals("0")) {
return "定位";
} else if (str.equals("1")) {
return "最近";
} else if (str.equals("2")) {
return "热门";
} else if (str.equals("3")) {
return "全部";
} else {
return "#";
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_TOUCH_SCROLL
|| scrollState == SCROLL_STATE_FLING) {
isScroll = true;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (!isScroll) {
return;
}
if (mReady) {
String text;
String name = allCity_lists.get(firstVisibleItem).getName();
String pinyin = allCity_lists.get(firstVisibleItem).getPinyi();
if (firstVisibleItem < 4) {
text = name;
} else {
text = PingYinUtil.converterToFirstSpell(pinyin)
.substring(0, 1).toUpperCase();
}
overlay.setText(text);
overlay.setVisibility(View.VISIBLE);
handler.removeCallbacks(overlayThread);
// 延迟一秒后执行,让overlay为不可见
handler.postDelayed(overlayThread, 1000);
}
}
}
接下来这些可以直接复制不需要操作的类,DatabaseHelper.java跟DBHelper.java 实现的是 查询我们存储城市文件的操作,在MyLetterListView.java中我们可以修改最右侧边栏的 a b c d 索引标签,PingYinUtil.javaPingYinUtil.java这个类里面实现的逻辑是拼音索引逻辑。详细的可以 看demo
demo 下载地址 :http://download.csdn.net/detail/ningzhouxu/9533169 (这是我自己又修改后的版本) 或者http://download.csdn.net/detail/ningzhouxu/9532845(这是美团原型)