Android自定义WheelView地区选择三级联动

本文实例为大家分享了WheelView地区选择三级联动的具体代码,供大家参考,具体内容如下

1. 效果

最近需要做一个地区选择的功能,但是在网上和github上找了很久都没找到满意的,然后朋友推荐了一个给我,我花了点时间把代码大致看懂并改成我想要的,并写上我的理解。效果如图:

2. 注意

a. 首先我们要明白,网上这写三级联动的demo,不管是把数据库文件放在raw还是assets中,我们都要进行复制,将这个文件复制到app目录下,即

/data/data/"+context.getPackageName()+"/databases/

至于到底放在raw还是assets中哪里好些,我也在网上查了下,见这篇博客这里点击 ,但是按照这里面说的好像.db文件最好放在assets中,但是这个demo中拿过来,原来的.db文件就是放在raw中,所以我也没改了。
b. 最重要的一点,因为我们一般都是将选择完以后的数据都要上传到服务器中,但是因为每个后台要求的不一样,所以对于这个地区的.db文件也要求不一样,所以我们最主要的是学会读取数据库文件然后通过代码形成联动,举个例子,比如美团有自己的一个数据库,我们定位湖南长沙芙蓉区,然后进行地区选择,将岳麓区上传服务器并且请求数据下来,但是我们一般不会直接上传文字,一个是怕重名,还有一个就是文字不会绝对的准确,比如两个字的地名黄山 和 黄 山,看起来都对,但是你们的后台服务器接受的参数是黄山,而且使用别人的数据库中使黄 山,那就出事了,所以我们一般都是传编码,但是每个数据库中城市编码一般都是不一样,所以我们需要找后台拿匹配的数据库文件或者js文件。如图所示,两份数据库,一份是朋友推荐自带的,例外一份是我们的。

我的数据库中省市区只有一个表,而那份却有三个表,省 市 区三个表。并且编码也不一样,可以明显看出来。

3. 干货

a. 布局就直接贴代码了,很简单,mainactivity中就一个按钮,而popupwindow中是三个wheelview,

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

 <LinearLayout
 android:id="@+id/ly_myinfo_changeaddress_child"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_alignParentBottom="true"
 android:background="#ffffff"
 android:orientation="vertical" >

 <RelativeLayout
 android:layout_width="match_parent"
 android:layout_height="44dp"
 >

 <View
 android:background="@color/silver"
 android:layout_width="match_parent"
 android:layout_height="0.5dp" />

 <TextView
 android:id="@+id/btn_myinfo_cancel"
 android:layout_width="wrap_content"
 android:layout_height="match_parent"
 android:paddingLeft="18dp"
 android:text="取消"
 android:gravity="center"
 android:layout_alignParentLeft="true"
 android:layout_marginRight="15dip"
 android:textColor="#e84515"
 android:textSize="14sp" />

 <TextView
 android:id="@+id/btn_myinfo_sure"
 android:layout_width="wrap_content"
 android:layout_height="match_parent"
 android:layout_alignParentRight="true"
 android:gravity="center"
 android:text="完成"
 android:textColor="#e84515"
 android:paddingRight="18dp"
 android:textSize="14sp" />

 </RelativeLayout>

 <View android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="#d8d8d8"/>

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="190dip"
 android:orientation="horizontal"
 android:gravity="center_vertical">

 <guozhaohui.com.wlylocationchoose.locationchoose.WheelView
 android:id="@+id/provinceView"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_weight="1"/>

 <guozhaohui.com.wlylocationchoose.locationchoose.WheelView
 android:id="@+id/cityView"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_weight="1"/>
 <guozhaohui.com.wlylocationchoose.locationchoose.WheelView
 android:id="@+id/districtView"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_weight="1"/>
 </LinearLayout>

 </LinearLayout>

</LinearLayout>

b. 因为上面说了,需要将文件copy到app目录下,所以直接最好这代码在application中写,

package guozhaohui.com.wlylocationchoose;

import android.app.Application;

import java.io.InputStream;

import guozhaohui.com.wlylocationchoose.locationchoose.CityDataHelper;

/**
 * Created by ${GuoZhaoHui} on 2017/2/13.
 * Abstract:
 */

public class MyApplication extends Application {

 private CityDataHelper dataHelper;

 @Override
 public void onCreate() {
 super.onCreate();

 /**
 * 放在application中,让app一启动就把raw中文件copy到 "/data/data/"+context.getPackageName()+"/databases/"
 * 这是app读取数据的方法,不管是将数据库文件放在raw或者assets中都是一样
 */
 dataHelper=CityDataHelper.getInstance(this);
 InputStream in = this.getResources().openRawResource(R.raw.city);
 dataHelper.copyFile(in,CityDataHelper.DATABASE_NAME,CityDataHelper.DATABASES_DIR);

 }
}

c. popupwindow不是本次的重点也直接贴代码。

 View popupView = LayoutInflater.from(this).inflate(R.layout.popup_locationchoose, null);
 mPopupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
 mPopupWindow.setTouchable(true);
 mPopupWindow.setFocusable(true);
 mPopupWindow.setOutsideTouchable(true);
 mPopupWindow.setAnimationStyle(R.style.popup_locationchoose_bottom);

 // pickText = (TextView)popupView.findViewById(R.id.tv_pickText);
 provinceView = (WheelView)popupView.findViewById(R.id.provinceView);
 cityView = (WheelView)popupView.findViewById(R.id.cityView);
 districtView = (WheelView)popupView.findViewById(R.id.districtView);

 //确定或者取消
 btn_myinfo_sure = (TextView)popupView.findViewById(R.id.btn_myinfo_sure);
 btn_myinfo_cancel = (TextView) popupView.findViewById(R.id.btn_myinfo_cancel);
 btn_myinfo_cancel.setOnClickListener(this);
 btn_myinfo_sure.setOnClickListener(this);

设置三个wheelview的可见条目数

provinceView.setVisibleItems(7);
cityView.setVisibleItems(7);
districtView.setVisibleItems(7);

为三个 wheelview添加滑动事件

 // 添加change事件
 provinceView.addChangingListener(this);
 // 添加change事件
 cityView.addChangingListener(this);
 // 添加change事件
 districtView.addChangingListener(this);

c. 拿到操作数据的对象SQLiteDatabase

 db = dataHelper.openDataBase();

观察数据库文件可知这表中是根据字段level来判断省市区的,如图

同时我们也可知这省市区三个模型中的字段都是一样的,都是

 private int cityID;
 private int parentId;
 private int level;
 private String name;
 private String pinyin;

不清楚的可以自己查下表,如图,我查一个省

所以我们建立一样的模型,虽然三个字段是一样的,建一个就可以了,但是为了标准最好还是建三个。

package guozhaohui.com.wlylocationchoose.locationchoose.model;

public class ProvinceModel {

 private int cityID;
 private int parentId;
 private int level;
 private String name;
 private String pinyin;

 public int getCityID() {
 return cityID;
 }

 public void setCityID(int cityID) {
 this.cityID = cityID;
 }

 public int getParentId() {
 return parentId;
 }

 public void setParentId(int parentId) {
 this.parentId = parentId;
 }

 public int getLevel() {
 return level;
 }

 public void setLevel(int level) {
 this.level = level;
 }

 public String getName() {
 return name;
 }

 public void setName(String name) {
 this.name = name;
 }

 public String getPinyin() {
 return pinyin;
 }

 public void setPinyin(String pinyin) {
 this.pinyin = pinyin;
 }

}

进行sql查询,将查询到的结果保存在cursor中,然后进行一行行的循环遍历,然后将遍历一行的对象添加到这个对象的集合中。这里得到省的集合。

 public List<ProvinceModel> getProvice(SQLiteDatabase db){
 String sql="SELECT * FROM ChooseCityModel where level = 1 ORDER BY cityID";
 Cursor cursor = db.rawQuery(sql,null);
 List<ProvinceModel> list=new ArrayList<ProvinceModel>();
 if (cursor!=null&&cursor.getCount() > 0) {
 while (cursor.moveToNext()){
 ProvinceModel provinceModel=new ProvinceModel();
 provinceModel.setCityID(cursor.getInt(cursor.getColumnIndex("cityID")));
 provinceModel.setParentId(cursor.getInt(cursor.getColumnIndex("parentId")));
 provinceModel.setLevel(cursor.getInt(cursor.getColumnIndex("level")));
 provinceModel.setName(cursor.getString(cursor.getColumnIndex("name")));
 provinceModel.setPinyin(cursor.getString(cursor.getColumnIndex("pinyin")));
 list.add(provinceModel);
 }
 }
 return list;
 }

根据表的结构,得到相应的sql语句,希望根据上一级省的cityId得到下面的市,其实换句话说本级市的parentId就是上一级的cityid,不清楚的可以将sql语句查一遍,验证下对不对,如图

得到相应省下面市的集合

 public List<CityModel> getCityByParentId(SQLiteDatabase db, String code){
 String sql="SELECT * FROM ChooseCityModel WHERE level = 2 and parentId = ? ORDER BY cityID";
 Cursor cursor = db.rawQuery(sql,new String[][code]);
 List<CityModel> list=new ArrayList<CityModel>();

 if (cursor!=null&&cursor.getCount() > 0) {

 while (cursor.moveToNext()){
 CityModel cityModel=new CityModel();
 cityModel.setCityID(cursor.getInt(cursor.getColumnIndex("cityID")));
 cityModel.setParentId(cursor.getInt(cursor.getColumnIndex("parentId")));
 cityModel.setLevel(cursor.getInt(cursor.getColumnIndex("level")));
 cityModel.setName(cursor.getString(cursor.getColumnIndex("name")));
 cityModel.setPinyin(cursor.getString(cursor.getColumnIndex("pinyin")));
 list.add(cityModel);
 }
 }
 return list;
 }

区也是一样的,直接贴代码了

 public List<DistrictModel> getDistrictById(SQLiteDatabase db, String code){
 //注意这里的parentId其实就是上一级的cityID
 String sql="SELECT * FROM ChooseCityModel WHERE level = 3 and parentId = ? ORDER BY cityID";
 Cursor cursor = db.rawQuery(sql,new String[][code]);
 List<DistrictModel> list=new ArrayList<DistrictModel>();
 if (cursor!=null&&cursor.getCount() > 0) {
 while (cursor.moveToNext()){
 DistrictModel districtModel=new DistrictModel();
 districtModel.setCityID(cursor.getInt(cursor.getColumnIndex("cityID")));
 districtModel.setParentId(cursor.getInt(cursor.getColumnIndex("parentId")));
 districtModel.setLevel(cursor.getInt(cursor.getColumnIndex("level")));
 districtModel.setName(cursor.getString(cursor.getColumnIndex("name")));
 districtModel.setPinyin(cursor.getString(cursor.getColumnIndex("pinyin")));
 list.add(districtModel);
 }
 }
 return list;
 }

d. 对弹出popuwindow显示的wheelview进行初始化,注释都写在代码里,

 private void initpopData() {
 //初始化数据
 dataHelper = CityDataHelper.getInstance(this);
 db = dataHelper.openDataBase();
 provinceDatas = dataHelper.getProvice(db);
 if (provinceDatas.size() > 0) {

 //弹出popup时,省wheelview中当前的省其实就是省集合的第一个
 mCurrentProvince = provinceDatas.get(0).getName();

 //根据省cityid查询到第一个省下面市的集合
 cityDatas = dataHelper.getCityByParentId(db, provinceDatas.get(0).getCityID()+"");
 }
 if (cityDatas.size() > 0) {
 //根据市cityid查询到第一个市集合下面区的集合
 districtDatas = dataHelper.getDistrictById(db, cityDatas.get(0).getCityID()+"");

 }
 //wheelview的适配器代码
 provinceAdapter = new ProvinceAdapter(this, provinceDatas);
 provinceAdapter.setTextSize(TEXTSIZE);//设置字体大小
 provinceView.setViewAdapter(provinceAdapter);

 updateCitys();
 updateAreas();
 }

更新省下面市的wheelview内容,注释很清楚,直接上代码

 private void updateCitys() {
 int pCurrent = provinceView.getCurrentItem();
 if (provinceDatas.size() > 0) {
 //这里是必须的的,上面得到的集合只是第一个省下面所有市的集合及第一个市下面所有区的集合
 //这里得到的是相应省下面对应市的集合
 cityDatas = dataHelper.getCityByParentId(db, provinceDatas.get(pCurrent).getCityID()+"");
 } else {
 cityDatas.clear();
 }
 citysAdapter = new CitysAdapter(this, cityDatas);
 citysAdapter.setTextSize(TEXTSIZE);
 cityView.setViewAdapter(citysAdapter);
 if (cityDatas.size() > 0) {
 //默认省下面 市wheelview滑动第一个,显示第一个市
 cityView.setCurrentItem(0);
 mCurrentCity = cityDatas.get(0).getName();
 } else {
 mCurrentCity = "";
 }
 updateAreas();
 }

第三个wheelview和第二个一样的,代码直接上

 private void updateAreas() {
 int cCurrent = cityView.getCurrentItem();
 if (cityDatas.size() > 0) {
 districtDatas = dataHelper.getDistrictById(db, cityDatas.get(cCurrent).getCityID()+"");
 } else {
 districtDatas.clear();
 }
 areaAdapter = new AreaAdapter(this, districtDatas);
 areaAdapter.setTextSize(TEXTSIZE);
 districtView.setViewAdapter(areaAdapter);
 if (districtDatas.size() > 0) {
 mCurrentDistrict = districtDatas.get(0).getName();
 districtView.setCurrentItem(0);
 } else {
 mCurrentDistrict = "";
 }
 }

4. 道友留步

1).因为我朋友也是在网上哪里找到的demo,所以这原版是谁的也不知道了。
2). 源码地址这里点击

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android使用GPS获取用户地理位置并监听位置变化的方法

    本文实例讲述了Android使用GPS获取用户地理位置并监听位置变化的方法.分享给大家供大家参考,具体如下: LocationActivity.java /* LocationActivity.java * @author octobershiner * 2011 7 22 * SE.HIT * 一个演示定位用户的位置并且监听位置变化的代码 * */ package uni.location; import android.app.Activity; import android.content

  • android 支持的语言列表(汇总)

    Arabic, Egypt (ar_EG) -----------------------------阿拉伯语,埃及Arabic, Israel (ar_IL) -------------------------------阿拉伯语,以色列Bulgarian, Bulgaria (bg_BG) ---------------------保加利亚语,保加利亚Catalan, Spain (ca_ES) ---------------------------加泰隆语,西班牙Czech, Czech

  • Android 获取系统语言的实例(兼容7.0)

    前言 获取系统当前语言是一个比较常用的功能,在 Android 7.0 系统上旧函数获取到的当前系统语言并不正确,或者说从 Android 7.0 起,Android 系统语言的规则变了. 下面是未适配 Android 7.0 的代码: //获取 Locale 的方式有二 //方式一 Locale locale = getResources().getConfiguration().locale; //方式二 Locale locale = Locale.getDefault(); //获取当前

  • Android编程获取地理位置的经度和纬度实例

    本文实例讲述了Android编程获取地理位置的经度和纬度.分享给大家供大家参考,具体如下: 在Android应用程序中,可以使用LocationManager来获取移动设备所在的地理位置信息.看如下实例:新建android应用程序TestLocation. 1.activity_main.xml布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_w

  • Android实现系统语言切换功能

    简单介绍下这个需求的缘由,这段时间因公司业务需要,其中有一项"设置系统语言"功能,就是在使用APP的过程中,动态的去切换整个Android机器的语言,具体参照手机设置页面有语言切换功能.起初想来是很简单的事情嘛,不就是个简单的资源国际化嘛,strings.xml资源文件一整还不给OK?真正动起手来就真不是这么一回事了,国际化是没问题,但是怎样能更改所有页面的文字资源呢,这是一个问题.下面介绍下网上找的几个方案. 一.API欺骗 烧制到手机中的android.jar包含了Android所

  • Android 各国语言缩写及简称详细介绍

    android资源文件夹的写法规则: 语言缩写-国家地区缩写 语言缩写请参阅: 国家地区缩写 en 英文 en_US 英文 (美国) ar 阿拉伯文 ar_AE 阿拉伯文 (阿拉伯联合酋长国) ar_BH 阿拉伯文 (巴林) ar_DZ 阿拉伯文 (阿尔及利亚) ar_EG 阿拉伯文 (埃及) ar_IQ 阿拉伯文 (伊拉克) ar_JO 阿拉伯文 (约旦) ar_KW 阿拉伯文 (科威特) ar_LB 阿拉伯文 (黎巴嫩) ar_LY 阿拉伯文 (利比亚) ar_MA 阿拉伯文 (摩洛哥) a

  • Android app应用多语言切换功能实现

    本文实例为大家分享了Android app应用实现多语言切换功能,供大家参考,具体内容如下 1.添加多语言文件 在不同的 value 文件夹下(例如 value .value-en.values-zh-rTW 文件夹)添加不同语言的 string.xml 文件,我们的项目添加了英文.简体中文.繁体中文三种语言,如下图所示: Project模式: Android模式: 其中英文需要翻译,繁体如果没有专门翻译的话,可以找个简繁转换网站,直接将简体中文转成繁体中文,推荐一个网站: http://www

  • 详解Android更改APP语言模式的实现过程

    一.效果图 二.描述 更改Android项目中的语言,这个作用于只用于此APP,不会作用于整个系统 三.解决方案 (一)布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" a

  • Android编程实现获取当前系统语言及地区并更改语言的方法

    本文实例讲述了Android编程实现获取当前系统语言及地区并更改语言的方法.分享给大家供大家参考,具体如下: 如果想获取手机的当前系统语言,可以通过Locale类获取,主要方法: Locale.getDefault().getLanguage() 返回的是es或者zh:通过 Locale.getDefault().getCountry() 获取当前国家或地区,返回为CN或US: 如果当前手机设置为中文-中国,则使用此方法返回zh-CN,同理可得到其他语言与地区的信息. 1.首先,如果要程序自动适

  • Android实现app应用多语言切换功能

    最近在做一个多语言切换的功能,类似于微信的语言切换,搜了下资料基本上都是以下这种: 1. 实现的效果 和微信类似,在设置界面打开切换语言的界面,选择语言后重启 HomeActivity,语言切换完成,下次重新打开 App ,也是用户设置的语言. 2. 实现步骤  1). 添加多语言文件  在不同的 value 文件夹下(例如 value .value-en.values-zh-rTW 文件夹)添加不同语言的 string.xml 文件,我们的项目添加了英文.简体中文.繁体中文三种语言,如下图所示

  • 用Android Location获取当前地理位置的方法

    在Android应用中,往往有获取当前地理位置的需求,比如微信获取附近的人需要获取用户当前的位置,不多说,直接上例子. 复制代码 代码如下: public Location getLocation() {// 获取Location通过LocationManger获取!  LocationManager locManger = (LocationManager) getSystemService(Context.LOCATION_SERVICE);  Location loc = locMange

  • 轻松实现Android仿淘宝地区选择功能

    最近用淘宝客户端的时候,编辑地址的时候有个地区选择的功能.看上面的效果觉得挺酷,滚动的时候,是最后一个从下面飞上来挨着前一个.就自己鼓捣一个出来玩玩. 说了效果可能不太直观,下面上两张图看看效果 淘宝地区选择效果 再来一张自己的效果 gif的效果可能不太好,大家自己用Android手机打开淘宝看看 实现分析 展示很简单,ListView就可以了.对于动画效果,只需要在getView的时候获取到要展示的View,通过属性动画修改translationY就ok啦.由于地区选择是一个界面,所以这里还用

随机推荐