android-wheel实现省、市、地区联动选择效果


我们都知道在IOS里面有个滚轮选择器,在Android中有人也实现了一个类似的,叫android-wheel。不过个人感觉实现的还是有点粗糙,这个后面再说。android-wheel给出了好几个不同类型的demo,不过里面的demo有个时间选择器(年月日选择)。没用过的可以去看看里面的demo,应对一般的都没什么大碍。由于公司项目要省、市、地区选择的功能,还要和IOS日期选择器一样,所以就研究了下android-wheel。下面说说我是如何实现省、市、地区选择的功能,还望大家指出其中的不足一起讨论。

首先是xml布局 (Activity_main.xml)


<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical"
android:background="@drawable/layout_bg">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingTop="30dp">
<kankan.wheel.widget.WheelViewandroid:id="@+id/provice"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="100dp"
/>
<kankan.wheel.widget.WheelViewandroid:id="@+id/city"
android:layout_height="wrap_content"
android:layout_width="100dp"/>
<kankan.wheel.widget.WheelViewandroid:id="@+id/area"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
</LinearLayout>
<Button
android:id="@+id/btnOK"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="确定"
/>
</LinearLayout>
在Activity_main.xml 文件中布局三个滚轮控件和一个按钮,三个滚轮分别是省、市、地区选择滚轮。最后按下按钮的时候Toast显示选择的省市地区和所选择的地址在数据库中的key。


数据库里面的数据是有一定查询规则的,如图所示:

android-wheel实现省、市、地区联动选择效果_如何

DQXX03为1,2,3分别代表省(直辖市)、市、地区。所以要获得所有省只需查询DQXX03为1就行了。如果要查询某个省下面的市呢?比如要查询河北省的所有市,可以这么写sql语句 select DQX_DQXX01 from DQXX where DQXX02="河北省"; 这样就查出来了河北省对应的DQX_DQXX01的值为13,然后根据这个值在通过select DQXX01,DQXX02 from DQXX  where DQX_DQXX01=13 就查询出来了每个市的对应键DQXX01的值为1301,1302,1303.......,查询地区也是类似的,这个时候根据DQX_DQXX01=1301或者1302.....查询对应的地区。最后省,市,地区连接起来就是DQXX05列里面的值,我们只要查询下就可以知道唯一地址DQXX01的值。


下面是主Activity文件


  1. package com.wheeltest;  

  2. import java.io.IOException;  

  3. import java.util.Map;  

  4. import kankan.wheel.widget.OnWheelScrollListener;  

  5. import kankan.wheel.widget.WheelView;  

  6. import kankan.wheel.widget.adapters.ArrayWheelAdapter;  

  7. import android.os.Bundle;  

  8. import android.os.Handler;  

  9. import android.app.Activity;  

  10. import android.content.Context;  

  11. import android.database.sqlite.SQLiteDatabase;  

  12. import android.graphics.Typeface;  

  13. import android.view.View;  

  14. import android.view.ViewGroup;  

  15. import android.widget.TextView;  

  16. import android.widget.Toast;  

  17. publicclass MainActivity extends Activity {  

  18. privatestaticfinal String TAG = "MainActivity";  

  19. privatestaticfinal String DBNAME = "dqxx.sqlite";  

  20. privatestaticfinal String TABLE_NAME = "dqxx";  

  21. private SQLiteDatabase db;  

  22. private Map<String, Integer> provinceMap;  

  23. private Map<String, Integer> cityMap;  

  24. private Map<String, Integer> areaMap;  

  25. private String[] provinceArray;  

  26. private String[] cityArray;  

  27. private String[] areaArray;  

  28. private WheelView provinceWheelView;  

  29. private WheelView cityWheelView;  

  30. private WheelView areaWheelView;  

  31. private ProviceCityAreaAdapter provinceAdapter;  

  32. private ProviceCityAreaAdapter cityAdapter;  

  33. private ProviceCityAreaAdapter areaAdapter;  

  34. private Handler mHandler = new Handler();  

  35. @Override

  36. protectedvoid onCreate(Bundle savedInstanceState) {  

  37. super.onCreate(savedInstanceState);  

  38.        setContentView(R.layout.activity_main);  

  39.        initWheelView();  

  40.        findViewById(R.id.btnOK).setOnClickListener(new View.OnClickListener() {  

  41. @Override

  42. publicvoid onClick(View arg0) {  

  43.                mHandler.postDelayed(new Runnable() {  

  44. @Override

  45. publicvoid run() {  

  46.                        StringBuilder sb = new StringBuilder();  

  47.                        sb.append(provinceArray[provinceWheelView.getCurrentItem()]);  

  48. if (provinceArray[provinceWheelView.getCurrentItem()].endsWith("市")) {  

  49.                            sb.append("市辖区");  

  50.                        }else {  

  51.                            sb.append(cityArray[cityWheelView.getCurrentItem()]);  

  52.                        }  

  53.                        sb.append(areaArray[areaWheelView.getCurrentItem()]);  

  54.                        Toast.makeText(MainActivity.this, sb.toString()+" key:"+DqxxUtils.findPrimaryKey(db, TABLE_NAME, sb.toString()), Toast.LENGTH_SHORT).show();  

  55.                    }  

  56.                }, 400);  

  57.            }  

  58.        });  

  59.    }  

  60. publicvoid initWheelView() {  

  61.        provinceWheelView = (WheelView)findViewById(R.id.provice);  

  62.        cityWheelView = (WheelView)findViewById(R.id.city);  

  63.        areaWheelView = (WheelView)findViewById(R.id.area);  

  64. //初始化省滚轮列表选择器

  65.        initProviceMap();  

  66.        provinceAdapter = new ProviceCityAreaAdapter(MainActivity.this, provinceArray, 0);  

  67.        provinceWheelView.setViewAdapter(provinceAdapter);  

  68.        provinceWheelView.setCurrentItem(0);  

  69.        provinceWheelView.addScrollingListener(privinceScrollListener);  

  70. //初始化城市滚轮列表选择器

  71.        String provinceName = provinceArray[0];  

  72. int dqx_dqxx01 = provinceMap.get(provinceName);  

  73. if (provinceName.endsWith("市")) {  

  74.            initCityMap(dqx_dqxx01, false);  

  75.        }else {  

  76.            initCityMap(dqx_dqxx01, true);  

  77.        }  

  78.        cityAdapter = new ProviceCityAreaAdapter(MainActivity.this, cityArray, 0);  

  79.        cityWheelView.setViewAdapter(cityAdapter);  

  80.        cityWheelView.setCurrentItem(0);  

  81.        cityWheelView.addScrollingListener(cityScrollListener);  

  82. //初始化地区滚轮列表选择器

  83.        String cityName = cityArray[0];  

  84. int dqx_dqxx01_2 = cityMap.get(cityName);  

  85.        provinceName = cityArray[0];  

  86. if (provinceName.endsWith("市")) {  

  87.            dqx_dqxx01_2 = dqx_dqxx01_2 * 100 +1;  

  88.        }  

  89.        initAreaMap(dqx_dqxx01_2);  

  90.        areaAdapter = new ProviceCityAreaAdapter(MainActivity.this, areaArray, 0);  

  91.        areaWheelView.setViewAdapter(areaAdapter);  

  92.        areaWheelView.setCurrentItem(0);  

  93.    }  

  94.    OnWheelScrollListener privinceScrollListener = new OnWheelScrollListener() {  

  95. @Override

  96. publicvoid onScrollingStarted(WheelView wheel) {  

  97.        }  

  98. @Override

  99. publicvoid onScrollingFinished(WheelView wheel) {  

  100. int currentItem = wheel.getCurrentItem();  

  101.            String provinceName = provinceArray[currentItem];  

  102. int dqxx01 = provinceMap.get(provinceName);  

  103. if (provinceName.endsWith("市")) {  

  104.                initCityMap(dqxx01, false);  

  105.            }else {  

  106.                initCityMap(dqxx01, true);  

  107.            }  

  108.            cityAdapter = new ProviceCityAreaAdapter(MainActivity.this, cityArray, 0);  

  109.            cityWheelView.setViewAdapter(cityAdapter);  

  110.            cityWheelView.setCurrentItem(0);  

  111.            String cityName = cityArray[0];  

  112. int dqx_dqxx01_2 = cityMap.get(cityName);  

  113. if (provinceName.endsWith("市")) {  

  114.                dqx_dqxx01_2 = dqx_dqxx01_2 * 100 +1;  

  115.            }  

  116.            initAreaMap(dqx_dqxx01_2);  

  117.            areaAdapter = new ProviceCityAreaAdapter(MainActivity.this, areaArray, 0);  

  118.            areaWheelView.setViewAdapter(areaAdapter);  

  119.            areaWheelView.setCurrentItem(0);  

  120.        }  

  121.    };  

  122.    OnWheelScrollListener cityScrollListener = new OnWheelScrollListener() {  

  123. @Override

  124. publicvoid onScrollingStarted(WheelView wheel) {  

  125.        }  

  126. @Override

  127. publicvoid onScrollingFinished(WheelView wheel) {  

  128.            String provinceName = provinceArray[provinceWheelView.getCurrentItem()];  

  129. int dqx_dqxx01 = cityMap.get(cityArray[wheel.getCurrentItem()]);  

  130. if (provinceName.endsWith("市")) {  

  131.                dqx_dqxx01 = dqx_dqxx01 * 100 +1;  

  132.            }  

  133.            initAreaMap(dqx_dqxx01);  

  134.            areaAdapter = new ProviceCityAreaAdapter(MainActivity.this, areaArray, 0);  

  135.            areaWheelView.setViewAdapter(areaAdapter);  

  136.            areaWheelView.setCurrentItem(0);  

  137.        }  

  138.    };  

  139. publicvoid initProviceMap() {  

  140. try {  

  141.            DqxxUtils.copyDB(MainActivity.this, DBNAME);  

  142. if (db == null) {  

  143.                db = openOrCreateDatabase(getFilesDir().getAbsolutePath() + "/" +DBNAME, Context.MODE_PRIVATE, null);  

  144.            }  

  145.            provinceMap = DqxxUtils.getProvince(db, TABLE_NAME);  

  146.            provinceArray = provinceMap.keySet().toArray(new String[provinceMap.size()]);  

  147.        } catch (IOException e) {  

  148.            e.printStackTrace();  

  149.        }  

  150.    }  

  151. publicvoid initCityMap(int dqx_dqxx01, boolean municipalities) {  

  152. try {  

  153.            DqxxUtils.copyDB(MainActivity.this, DBNAME);  

  154. if (db == null) {  

  155.                db = openOrCreateDatabase(getFilesDir().getAbsolutePath() + "/" +DBNAME, Context.MODE_PRIVATE, null);  

  156.            }  

  157.            cityMap = DqxxUtils.getCity(db, TABLE_NAME, dqx_dqxx01, municipalities);  

  158.            cityArray = cityMap.keySet().toArray(new String[cityMap.size()]);  

  159.        } catch (IOException e) {  

  160.            e.printStackTrace();  

  161.        }  

  162.    }  

  163. publicvoid initAreaMap(int dqx_dqxx01) {  

  164. try {  

  165.            DqxxUtils.copyDB(MainActivity.this, DBNAME);  

  166. if (db == null) {  

  167.                db = openOrCreateDatabase(getFilesDir().getAbsolutePath() + "/" +DBNAME, Context.MODE_PRIVATE, null);  

  168.            }  

  169.            areaMap = DqxxUtils.getArea(db, TABLE_NAME, dqx_dqxx01);  

  170.            areaArray = areaMap.keySet().toArray(new String[areaMap.size()]);  

  171.        } catch (IOException e) {  

  172.            e.printStackTrace();  

  173.        }  

  174.    }  

  175. publicclass ProviceCityAreaAdapter extends ArrayWheelAdapter<String> {  

  176. privateint currentItem;  

  177. privateint currentValue;  

  178. public ProviceCityAreaAdapter(Context context, String[] items, int current) {  

  179. super(context, items);  

  180. this.currentValue = current;  

  181.        }  

  182. publicvoid setCurrentValue(int value){  

  183. this.currentValue = value;  

  184.        }  

  185. @Override

  186. protectedvoid configureTextView(TextView view) {  

  187. super.configureTextView(view);  

  188. //          if (currentItem == currentValue) {

  189. //              view.setTextColor(0xFF0000F0);

  190. //          }

  191.            view.setTypeface(Typeface.SANS_SERIF);  

  192.        }  

  193. @Override

  194. public View getItem(int index, View convertView, ViewGroup parent) {  

  195.            currentItem = index;  

  196. returnsuper.getItem(index, convertView, parent);  

  197.        }  

  198.    }  

  199. @Override

  200. protectedvoid onDestroy() {  

  201. if (db != null) {  

  202.            db.close();  

  203.            db = null;  

  204.        }  

  205. super.onDestroy();  

  206.    }  

首先定义了三个数组,分别用来装查询到的省,市和地区,其实在这三个之中,省份是不会动态变得。每次都一样,关键就在于,每次省滚轮改变后要查询到对应的市和市对应的地区数据,要及时查询出来,不然会有卡顿的感觉,流畅性不好。我的数据库起初是放在assert目录下面,然后把它写到应用程序对应的/data/data/包名/files目录下,然后在该目录下打开数据库。这里涉及到一些缓冲和效率方面的东西,我现在是公用全局的SQLiteDatabase对象db,不是每次都打开数据库。然后每次查询都只查询出对用所需要的列的数据来,这个可以加快查询。本来我想实现滚轮选择某个数据的时候该数据行深色显示,但是发现好像挺难实现的,android-wheel好像做的不是很强大,也可能是我愚笨没找到实现的方法吧。有知道的麻烦说句啊,谢了。


最后一个类是工具类,包含一些数据库操作和文件读写的。我就不贴出来了。我已经把这个工程放到Github上去了地址https://github.com/ywenblocker/Provinces-Picker-wheel大家可以看看,有问题也欢迎提出来。最后附上一张效果图。

android-wheel实现省、市、地区联动选择效果_项目_02