1 概述
主要就是在上篇中的RegionFragment里实现区域查询的功能,为了增加用户体验,添加了用拼音或者拼音首字母查询的功能。
2 布局
界面布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="#696969" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/region_edit_text" android:layout_width="0dp" android:layout_weight="1" android:layout_height="45sp"/> <Button android:id="@+id/search_button" android:layout_width="45sp" android:layout_height="45sp" android:background="@drawable/search"/> </LinearLayout> <ListView android:id="@+id/regions_list_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout>
可以看到总体布局包含了一个上面的线性布局和一个下面的用来现实查询结果的ListView,上面的线性布局包含了一个用来输入查询条件的EditText和一个查询按钮。
ListView的Item布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/county_name" android:textSize="20sp" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:id="@+id/province_city_name" android:textSize="15sp" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout>
包含了上下两个TextView,上面的用大字体显示县名,下面的用小字体现实省名加市名。
3 代码逻辑
业务逻辑主要在RegionFragment里,同时因为我们用到了ListView,所以应该实现一个ArrayAdapter<CityCode>的子类RegionAdapter。
3.1 RegionFragment.java
public class RegionFragment extends Fragment implements View.OnClickListener,
AdapterView.OnItemClickListener {
private List<CityCode> cityCodeList = new ArrayList<CityCode>();
private EditText regionEditText;
private Button searchButton;
private ListView regionListView;
private RegionAdapter regionAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.region_layout, container, false);
regionAdapter = new RegionAdapter(getActivity(),
R.layout.region_item_layout, cityCodeList);
regionEditText = (EditText) view.findViewById(R.id.region_edit_text);
searchButton = (Button) view.findViewById(R.id.search_button);
regionListView = (ListView) view.findViewById(R.id.regions_list_view);
regionListView.setAdapter(regionAdapter);
regionListView.setOnItemClickListener(this);
searchButton.setOnClickListener(this);
return view;
}
@Override
public void onClick(View v) {
String regionName = regionEditText.getText().toString();
if (TextUtils.isEmpty(regionName)) {
Toast.makeText(getActivity(), "请输入地名!", Toast.LENGTH_SHORT).show();
return;
}
cityCodeList.clear();
if (regionName.matches("^[a-zA-Z]*")) {
List<CityCode> tmpList = DataSupport.where(
"spell like ? OR firstspell like ?",
regionName, regionName).find(CityCode.class);
for (CityCode cc : tmpList) {
cityCodeList.add(cc);
}
} else {
List<CityCode> tmpList = DataSupport.where("spell like ?",
regionName).find(CityCode.class);
for (CityCode cc : tmpList) {
cityCodeList.add(cc);
}
}
regionAdapter.notifyDataSetChanged();
}
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
}
}
onCreateview里的代码很简单,就是获取了布局中的各个控件,创建了一个RegionAdapter,设置了listView的Adapter和Item Click事件以及按钮的监听事件,下面我们讲按钮监听事件的具体逻辑:
首先从regionEditText中获取字符串并判断是否为空(当regionName是null或者""TextUtils.isEmpty()方法都返回true),空的给个提示,清空cityCodeList,然后通过正则表达式判断regionName是中文还是拼音,根据结果确定查询条件,这里有两点注意:
一是litepal中多条件查询的用法DataSupport.where(String… conditions).find(Class<T> modelClass),返回的是一个List<T>,其中find函数没什么好说的,where的参数是非固定个数的字符串,第一个字符串的格式对应于"where columnName = ?",不过格式是"columnname like ?"如果多个判断条件用OR或者AND隔开,后面的字符串对应此字符串中的问好。
二是cityCodeList不能直接通过find方法返回,这点原因我也不太明白,因为经过调试我发现如果通过find方法直接返回得到,cityCodeList的值没有任何问题,但是ListView不显示,必须遍历find返回结果,把每个CityCode添加到CityList才可以。
3.2 RegionAdapter.java
public class RegionAdapter extends ArrayAdapter<CityCode> {
private int resourceId;
public RegionAdapter(Context context, int resource, List<CityCode> objects) {
super(context, resource, objects);
resourceId = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
CityCode cityCode = getItem(position);
View view;
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(getContext()).inflate(resourceId, null);
viewHolder = new ViewHolder();
viewHolder.countyName = (TextView) view.findViewById(R.id.county_name);
viewHolder.provinceAndCityName = (TextView) view.findViewById(
R.id.province_city_name);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.countyName.setText(cityCode.getCounty());
viewHolder.provinceAndCityName.setText(cityCode.getProvince() + ", "
+ cityCode.getCity());
return view;
}
class ViewHolder {
TextView countyName;
TextView provinceAndCityName;
}
}
重写了构造方法,构造方法包含3个参数Context, 布局文件的resourceId,和数据。因为在Fragment中,context可以通过getActivity得到,布局文件就是上面的那个,数据就是cityCodeList。添加了resourceId字段,这样可以通过inflate方法获取listView的Item的View。
下面主要将getView方法,首先通过LayoutInflater.from(getContext()).inflate(resourceId, null)获取view,然后对view上面的控件进行设置,这里用到了两个优化技巧:
一是先判断convertView是否为空,converView这个参数用于将之前加载好的布局进行缓存,以便之后重用,当convetView不空时,可以直接将convertView赋值给view。
二是将布局于内部类ViewHolder相关联,这样对布局内的控件操作可以直接通过对成员变量的操作来完成,而不用每次用findViewById得到控件,减少了运算量。