Android ListView城市列表,按a-z分组字母索引排序

       在上一篇中实现了,先自定义数据源,使Adapter通过实现SectionIndexer接口给ListView分组,并用Collections.sort对数据list进行排序。

       但是Collections.sort并不高效,如果数据源太多,必然会太耗时,所以这篇使用android.widget.Filterable自动筛选城市。

       Filterable定义了一种可过滤的行为:
protected FilterResults  performFiltering(CharSequence prefix)方法定义过滤条件
protected void publishResults(CharSequence constraint, FilterResults results)发布筛选过后得到的数据同时更新Adapter更新。

       这篇代码是在上一篇的基础上改造的,就多了SearchCityAdapter(使用了Filterable)和city.db以及一些数据库操作的类。先看一下源码结构目录(去掉了CharacterParser(汉字转换成拼音的类)和Collections.sort方法):


       上几张运行截图效果:


       先看SearchCityAdapter:

public class SearchCityAdapter extends BaseAdapter implements Filterable {

	private List<City> mAllCities;
	private List<City> mResultCities;
	private LayoutInflater mInflater;
	private Context mContext;

	// private String mFilterStr;

	public SearchCityAdapter(Context context, List<City> allCities) {
		mContext = context;
		mAllCities = allCities;
		mResultCities = new ArrayList<City>();
		mInflater = LayoutInflater.from(mContext);
	}

	@Override
	public int getCount() {
		return mResultCities.size();
	}

	@Override
	public City getItem(int position) {
		return mResultCities.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.search_city_item, null);
		}
		TextView provinceTv = (TextView) convertView
				.findViewById(R.id.search_province);
		provinceTv.setText(mResultCities.get(position).getProvince());
		TextView cityTv = (TextView) convertView
				.findViewById(R.id.column_title);
		cityTv.setText(mResultCities.get(position).getCity());
		return convertView;
	}

	@Override
	public Filter getFilter() {
		Filter filter = new Filter() {
			protected void publishResults(CharSequence constraint,
					FilterResults results) {
				mResultCities = (ArrayList<City>) results.values;
				if (results.count > 0) {
					notifyDataSetChanged();
				} else {
					notifyDataSetInvalidated();
				}
			}

			protected FilterResults performFiltering(CharSequence s) {
				String str = s.toString().toUpperCase();
				// mFilterStr = str;
				FilterResults results = new FilterResults();
				ArrayList<City> cityList = new ArrayList<City>();
				if (mAllCities != null && mAllCities.size() != 0) {
					for (City cb : mAllCities) {
						// 匹配全屏、首字母、和城市名中文
						if (cb.getAllFristPY().indexOf(str) > -1
								|| cb.getAllPY().indexOf(str) > -1
								|| cb.getCity().indexOf(str) > -1) {
							cityList.add(cb);
						}
					}
				}
				results.values = cityList;
				results.count = cityList.size();
				return results;
			}
		};
		return filter;
	}

}
通过
<pre name="code" class="java"><pre name="code" class="java">				if (mAllCities != null && mAllCities.size() != 0) {
					for (City cb : mAllCities) {
						// 匹配全屏、首字母、和城市名中文
						if (cb.getAllFristPY().indexOf(str) > -1
								|| cb.getAllPY().indexOf(str) > -1
								|| cb.getCity().indexOf(str) > -1) {
							cityList.add(cb);
						}
					}
				}
				results.values = cityList;
				results.count = cityList.size();
				return results;
	

 
 
 
 
过滤并把结果回传给results,在

protected void publishResults(CharSequence constraint,
					FilterResults results) {
				mResultCities = (ArrayList<City>) results.values;
				if (results.count > 0) {
					notifyDataSetChanged();
				} else {
					notifyDataSetInvalidated();
				}
			}
中,如果过滤得到的 results非空,则调用notifyDataSetChanged方法强制调用getView来刷新每个Item的内容。否则调用notifyDataSetInvalidated()会重绘View。
重新改造一下activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.testbase.ClearEditText
        android:id="@+id/et_msg_search"
        android:layout_width="match_parent"
        android:layout_height="48.0dip"   
        android:background="@drawable/base_edit_input"
        android:drawableLeft="@drawable/icon_msg_search"
        android:drawablePadding="10dp"
        android:hint="@string/city_search_hint"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:singleLine="true" />

    <RelativeLayout
        android:id="@+id/layout_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/base_bg"
        android:orientation="vertical" >

        <RelativeLayout
            android:id="@+id/city_content_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="top"
            android:background="@drawable/content_bg"
            android:orientation="horizontal" >

            <ListView
                android:id="@+id/list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:cacheColorHint="#00000000"
                android:scrollbars="none" />

            <TextView
                android:id="@+id/tv_mid_letter"
                android:layout_width="80.0dip"
                android:layout_height="80.0dip"
                android:layout_centerInParent="true"
                android:layout_gravity="center"
                android:background="@drawable/letter_mid_view_background"
                android:gravity="center"
                android:padding="5dip"
                android:textColor="@color/base_actionbar_bg"
                android:textSize="35.0dip"
                android:visibility="invisible" />
            
              <!-- 加载数据库时间太长 -->

            <include
                android:id="@+id/citys_list_load"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_centerInParent="true"
                android:layout_gravity="center"
                layout="@layout/base_load_empty_layout" />
            
            
              <com.example.testbase.MyLetterSortView
            android:id="@+id/right_letter"
            android:layout_width="25dip"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:background="@color/transparent" />
        </RelativeLayout>

          <FrameLayout
            android:id="@+id/search_content_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <ListView
                android:id="@+id/search_list"
                style="@style/base_listview_style"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:cacheColorHint="#00000000"
                android:focusableInTouchMode="true"
                android:visibility="gone" />

            <TextView
                android:id="@+id/search_empty"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="10.0dip"
                     android:drawableTop="@drawable/icon_result"
                    android:drawablePadding="50dp"
                    android:text="亲,貌似没有找到额……"
                android:visibility="gone" />
        </FrameLayout>
      
    </RelativeLayout>

</LinearLayout>

       就添加了加载城市列表时的Loading视图和搜索无结果的TextView。再这样设置一下就OK了:

mSearchListView.setEmptyView(findViewById(R.id.search_empty));

listView.setEmptyView(findViewById(R.id.citys_list_load));

       最后再来看看LetterSortActivity:

public class LetterSortActivity extends Activity implements OnClickListener {

	public static final String TAG = LetterSortActivity.class.getSimpleName();

	private Context context = LetterSortActivity.this;

	private ClearEditText mClearEditText;
	private TextView tv_mid_letter;
	private ListView listView;
	private MyLetterSortView right_letter;

	private ItemBeanAdapter mAdapter;
	private List<City> mlist = new ArrayList<City>();
	private InputMethodManager inputMethodManager;

	private View mCityContainer;
	private FrameLayout mSearchContainer;
	private ListView mSearchListView;
	private SearchCityAdapter mSearchCityAdapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		initView();
		setLinstener();
		initData();
		fillData();
	}

	protected void initData() {

		getDataCity();
		mAdapter = new ItemBeanAdapter(this, mlist);
		listView.setEmptyView(findViewById(R.id.citys_list_load));
		listView.setAdapter(mAdapter);

	}

	protected void initView() {

		inputMethodManager = (InputMethodManager) this
				.getSystemService(Context.INPUT_METHOD_SERVICE);
		listView = (ListView) findViewById(R.id.list);
		mClearEditText = (ClearEditText) findViewById(R.id.et_msg_search);
		// 这里设置中间字母
		right_letter = (MyLetterSortView) findViewById(R.id.right_letter);
		tv_mid_letter = (TextView) findViewById(R.id.tv_mid_letter);
		right_letter.setTextView(tv_mid_letter);		
		//搜索		
		mCityContainer = findViewById(R.id.city_content_container);
		mSearchContainer = (FrameLayout) this.findViewById(R.id.search_content_container);
		mSearchListView = (ListView) findViewById(R.id.search_list);
		mSearchListView.setEmptyView(findViewById(R.id.search_empty));
		mSearchContainer.setVisibility(View.GONE);

	}

	protected void setLinstener() {

		// tv_reget_pwd.setOnClickListener(this);

		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				T.showShort(getApplicationContext(),
						((City) mAdapter.getItem(position)).toString());

			}
		});

		listView.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// 隐藏软键盘
				if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
					if (getCurrentFocus() != null)
						inputMethodManager.hideSoftInputFromWindow(
								getCurrentFocus().getWindowToken(),
								InputMethodManager.HIDE_NOT_ALWAYS);
				}
				return false;
			}
		});

		// 设置右侧触摸监听
		right_letter
				.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {

					@Override
					public void onTouchingLetterChanged(String s) {
						// 该字母首次出现的位置
						int position = mAdapter.getPositionForSection(s
								.charAt(0));
						if (position != -1) {
							listView.setSelection(position);
						}

					}
				});

		// 根据输入框输入值的改变来过滤搜索
		mClearEditText.addTextChangedListener(new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
				// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
				filterData2(s.toString());
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {

			}

			@Override
			public void afterTextChanged(Editable s) {
			}
		});

		mSearchListView
				.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {

					@Override
					public void onItemClick(AdapterView<?> parent, View view,
							int position, long id) {
						// TODO Auto-generated method stub
						// L.i(mSearchCityAdapter.getItem(position).toString());
						T.showLong(getApplicationContext(), mSearchCityAdapter
								.getItem(position).toString());
					}
				});
	}

	protected void fillData() {
		// TODO Auto-generated method stub

	}

	private void getDataCity() {

		new Thread(new Runnable() {

			@Override
			public void run() {
				MyCityDBHelper myCityDBHelper = new MyCityDBHelper(context);

				mlist = myCityDBHelper.getCityDB().getAllCity();
				mHandler.sendEmptyMessage(0);

			}
		}).start();

		// 对list进行排序
		// Collections.sort(mlist, new PinyinComparator() {
		// });

	}

	

	private void filterData2(String filterStr) {
		mSearchCityAdapter = new SearchCityAdapter(LetterSortActivity.this,
				mlist);
		mSearchListView.setAdapter(mSearchCityAdapter);
		mSearchListView.setTextFilterEnabled(true);
		if (mlist.size() < 1 || TextUtils.isEmpty(filterStr)) {
			mCityContainer.setVisibility(View.VISIBLE);
			mSearchContainer.setVisibility(View.INVISIBLE);

		} else {

			mCityContainer.setVisibility(View.INVISIBLE);
			mSearchContainer.setVisibility(View.VISIBLE);
			mSearchCityAdapter.getFilter().filter(filterStr);
		}
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		//
		default:
			break;
		}

	}

	private Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 0:

				mAdapter.updateListView(mlist);
				break;
			default:
				break;
			}
		}
	};
}

       和上一篇中的代码大同小异。就改了两个地方,一个是初始化数据,上一篇中是自定义的随机字符串,并使用Collections.sort对list进行排序。这一篇中使用了直接从city.db中获取数据,因为使用的是Cursor c = db.rawQuery("SELECT * from " + CITY_TABLE_NAME+" order by firstpy", null);所以不需要排序。

       另一个修改的地方就是filterData()方法了,这里主要是mSearchCityAdapter.getFilter().filter(filterStr);把过滤条件交给它就OK了。

       当然,你仍然可以像上一篇中那样先筛选数据,再使用Collections.sort排序,最后更新ListView。代码如下:

private void filterData(String filterStr) {
		List<City> filterDateList = new ArrayList<City>();
		if (TextUtils.isEmpty(filterStr)) {
			mAdapter.updateListView(mlist);
		} else {
			filterDateList.clear();
			for (City city : mlist) {
				String name = city.getCity();
				if (name != null) {
					if (name.indexOf(filterStr.toString()) != -1
							|| CharacterParser.getInstance().getSelling(name)
									.startsWith(filterStr.toString())) {
						filterDateList.add(city);
					}
				}
			}
			Collections.sort(filterDateList, new PinyinComparator() {
			});

			mAdapter.updateListView(filterDateList);
		}

	}

       这样的话,你会发现搜索城市的时候有时会有点迟钝,这是因为数据有点多……

你还可以这样尝试:

       查询数据库的时候Cursor c = db.rawQuery("SELECT * from " + CITY_TABLE_NAME, null);

不使用order by 。然后再通过Collections.sort排序,哇咔咔,要好几秒啊才能把城市数据列表加载出来啊,没办法,数据有点多。

       就写到这里吧!

DEMO下载地址http://download.csdn.net/detail/yalinfendou/8616375


猜你喜欢

转载自blog.csdn.net/yalinfendou/article/details/45170473
今日推荐