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

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


首先是xml布局 (Activity_main.xml)

  
  
  
  
<LinearLayout xmlns: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.WheelView android:id= "@+id/provice"
             android:layout_height= "wrap_content"
             android:layout_width= "wrap_content"
             android:minWidth= "100dp"
             />
         <kankan.wheel.widget.WheelView android:id= "@+id/city"
             android:layout_height= "wrap_content"
             android:layout_width= "100dp" />
         <kankan.wheel.widget.WheelView android: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。

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


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文件

package com.wheeltest;

import java.io.IOException;
import java.util.Map;

import kankan.wheel.widget.OnWheelScrollListener;
import kankan.wheel.widget.WheelView;
import kankan.wheel.widget.adapters.ArrayWheelAdapter;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Typeface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	private static final String TAG = "MainActivity";
	private static final String DBNAME = "dqxx.sqlite";
	private static final String TABLE_NAME = "dqxx";
	private SQLiteDatabase db;
	private Map<String, Integer> provinceMap;
	private Map<String, Integer> cityMap;
	private Map<String, Integer> areaMap;

	private String[] provinceArray;
	private String[] cityArray;
	private String[] areaArray;

	private WheelView provinceWheelView;
	private WheelView cityWheelView;
	private WheelView areaWheelView;

	private ProviceCityAreaAdapter provinceAdapter;
	private ProviceCityAreaAdapter cityAdapter;
	private ProviceCityAreaAdapter areaAdapter;
	private Handler mHandler = new Handler();
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		initWheelView();

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

			@Override
			public void onClick(View arg0) {
				mHandler.postDelayed(new Runnable() {

					@Override
					public void run() {
						StringBuilder sb = new StringBuilder();
						sb.append(provinceArray[provinceWheelView.getCurrentItem()]);
						if (provinceArray[provinceWheelView.getCurrentItem()].endsWith("市")) {
							sb.append("市辖区");
						}else {
							sb.append(cityArray[cityWheelView.getCurrentItem()]);
						}
						sb.append(areaArray[areaWheelView.getCurrentItem()]);

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

			}
		});
	}

	public void initWheelView() {
		provinceWheelView = (WheelView)findViewById(R.id.provice);
		cityWheelView = (WheelView)findViewById(R.id.city);
		areaWheelView = (WheelView)findViewById(R.id.area);

		//初始化省滚轮列表选择器
		initProviceMap();
		provinceAdapter = new ProviceCityAreaAdapter(MainActivity.this, provinceArray, 0);
		provinceWheelView.setViewAdapter(provinceAdapter);
		provinceWheelView.setCurrentItem(0);
		provinceWheelView.addScrollingListener(privinceScrollListener);

		//初始化城市滚轮列表选择器
		String provinceName = provinceArray[0];
		int dqx_dqxx01 = provinceMap.get(provinceName);
		if (provinceName.endsWith("市")) {
			initCityMap(dqx_dqxx01, false);
		}else {
			initCityMap(dqx_dqxx01, true);
		}
		cityAdapter = new ProviceCityAreaAdapter(MainActivity.this, cityArray, 0);
		cityWheelView.setViewAdapter(cityAdapter);
		cityWheelView.setCurrentItem(0);
		cityWheelView.addScrollingListener(cityScrollListener);

		//初始化地区滚轮列表选择器
		String cityName = cityArray[0];
		int dqx_dqxx01_2 = cityMap.get(cityName);
		provinceName = cityArray[0];
		if (provinceName.endsWith("市")) {
			dqx_dqxx01_2 = dqx_dqxx01_2 * 100 +1;
		}
		initAreaMap(dqx_dqxx01_2);
		areaAdapter = new ProviceCityAreaAdapter(MainActivity.this, areaArray, 0);
		areaWheelView.setViewAdapter(areaAdapter);
		areaWheelView.setCurrentItem(0);

	}


	OnWheelScrollListener privinceScrollListener = new OnWheelScrollListener() {

		@Override
		public void onScrollingStarted(WheelView wheel) {
		}

		@Override
		public void onScrollingFinished(WheelView wheel) {
			int currentItem = wheel.getCurrentItem();
			String provinceName = provinceArray[currentItem];
			int dqxx01 = provinceMap.get(provinceName);
			if (provinceName.endsWith("市")) {
				initCityMap(dqxx01, false);
			}else {
				initCityMap(dqxx01, true);
			}

			cityAdapter = new ProviceCityAreaAdapter(MainActivity.this, cityArray, 0);
			cityWheelView.setViewAdapter(cityAdapter);
			cityWheelView.setCurrentItem(0);

			String cityName = cityArray[0];
			int dqx_dqxx01_2 = cityMap.get(cityName);
			if (provinceName.endsWith("市")) {
				dqx_dqxx01_2 = dqx_dqxx01_2 * 100 +1;
			}
			initAreaMap(dqx_dqxx01_2);
			areaAdapter = new ProviceCityAreaAdapter(MainActivity.this, areaArray, 0);
			areaWheelView.setViewAdapter(areaAdapter);
			areaWheelView.setCurrentItem(0);
		}
	};


	OnWheelScrollListener cityScrollListener = new OnWheelScrollListener() {

		@Override
		public void onScrollingStarted(WheelView wheel) {
		}

		@Override
		public void onScrollingFinished(WheelView wheel) {
			String provinceName = provinceArray[provinceWheelView.getCurrentItem()];
			int dqx_dqxx01 = cityMap.get(cityArray[wheel.getCurrentItem()]);
			if (provinceName.endsWith("市")) {
				dqx_dqxx01 = dqx_dqxx01 * 100 +1;
			}
			initAreaMap(dqx_dqxx01);
			areaAdapter = new ProviceCityAreaAdapter(MainActivity.this, areaArray, 0);
			areaWheelView.setViewAdapter(areaAdapter);
			areaWheelView.setCurrentItem(0);
		}
	};


	public void initProviceMap() {
		try {
			DqxxUtils.copyDB(MainActivity.this, DBNAME);
			if (db == null) {
				db = openOrCreateDatabase(getFilesDir().getAbsolutePath() + "/" +DBNAME, Context.MODE_PRIVATE, null);
			}
			provinceMap = DqxxUtils.getProvince(db, TABLE_NAME);
			provinceArray = provinceMap.keySet().toArray(new String[provinceMap.size()]);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void initCityMap(int dqx_dqxx01, boolean municipalities) {
		try {
			DqxxUtils.copyDB(MainActivity.this, DBNAME);
			if (db == null) {
				db = openOrCreateDatabase(getFilesDir().getAbsolutePath() + "/" +DBNAME, Context.MODE_PRIVATE, null);
			}
			cityMap = DqxxUtils.getCity(db, TABLE_NAME, dqx_dqxx01, municipalities);
			cityArray = cityMap.keySet().toArray(new String[cityMap.size()]);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void initAreaMap(int dqx_dqxx01) {
		try {
			DqxxUtils.copyDB(MainActivity.this, DBNAME);
			if (db == null) {
				db = openOrCreateDatabase(getFilesDir().getAbsolutePath() + "/" +DBNAME, Context.MODE_PRIVATE, null);
			}
			areaMap = DqxxUtils.getArea(db, TABLE_NAME, dqx_dqxx01);
			areaArray = areaMap.keySet().toArray(new String[areaMap.size()]);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}



	public class ProviceCityAreaAdapter extends ArrayWheelAdapter<String> {
		private int currentItem;
		private int currentValue;

		public ProviceCityAreaAdapter(Context context, String[] items, int current) {
			super(context, items);
			this.currentValue = current;
		}


		public void setCurrentValue(int value){
			this.currentValue = value;
		}

		@Override
		protected void configureTextView(TextView view) {
			super.configureTextView(view);
//			if (currentItem == currentValue) {
//				view.setTextColor(0xFF0000F0);
//			}
			view.setTypeface(Typeface.SANS_SERIF);
		}

		@Override
		public View getItem(int index, View convertView, ViewGroup parent) {
			currentItem = index;
			return super.getItem(index, convertView, parent);
		}

	}

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

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


最后说句,该工程用到的数据库是公司项目的,不好意思,不能开源,还望见谅。除了这个其他东西都有。


你可能感兴趣的:(android,城市选择器,android-wheel,地区区域选择器,省市地区选择器)