1. 程式人生 > >使用Android-PickerView實現地址選擇器時間選擇器

使用Android-PickerView實現地址選擇器時間選擇器

這裡貢獻下我使用Android-PickerView實現地址選擇器遇到的坑,算是一個筆記。首先要吐槽下後臺介面,為了實現移動端和web端的統一(ps:可能他沒搞過後臺介面),修改地址的時候本來要用下拉框。。。我去,後面ios的大兄弟苦苦哀求,改成了他們ios的PickerView,就是地址選擇聯動的,我一想也可以,不是有個大兄弟老早就封裝了精仿這個PickerView嗎,美美的~可是有點曲折

大寫的挽尊,我去

這個大兄弟已經離開程式設計界了,雖然這也是我的終極目標,嘿嘿

這裡寫圖片描述

好吧,我們只能做一些摸索了,還好留下了demo,這個控制元件堪稱完美,兄弟們可以一起去用用,大家交流體驗。做那種滾動選項選擇的不在話下,用了這個,就可以跟ios的大兄弟同步了,當然我不再介紹這裡的時間選擇器,資料固定已經封裝。弱水三千,我取一瓢飲。我這裡只拿選項選擇器來進行地址滾動選擇器(省、市、區三級聯動)的用法。主要是資料不統一性,我不改動pickerView已封裝好的控制元件,只在使用上下個道道。
欲哭無淚的是,我這邊的後臺資料介面需要我這邊修改地址選擇提交的是id,就像ERP系統的下拉框一樣,展示的時候顯示鍵(name),實際提交的時候是提交值(id),有點點噁心,但是噁心也有個噁心的做法。然後我這邊的資料庫只做查詢操作,所以直接生成後,放在assert檔案下讀取使用了,當然你還會發現更好的做法,大兄弟,你可以帶帶我~~

一、首先是新增依賴

 compile 'com.bigkoo:pickerview:2.1.1'

二、然後你就可以歡快地去使用了,網上有可以直接讀取assert資料夾下資料庫的方法,稍微封裝了下。還有幾個bean實體類,用於儲存城市編碼,省份id,等欄位(最重要的是要儲存id做後續修改提交的引數)。

1、讀取assert下的sqlite資料庫

package db;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import
android.database.sqlite.SQLiteDatabase; import android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; /** * This is a Assets Database Manager * Use it, you can use a assets database file in you application * It will copy the database file to "/data/data/[your application package name]/database" when you first time you use it * Then you can get a SQLiteDatabase object by the assets database file * @author
RobinTang * @time 2012-09-20 * * * How to use: * 1. Initialize AssetsDatabaseManager * 2. Get AssetsDatabaseManager * 3. Get a SQLiteDatabase object through database file * 4. Use this database object * * Using example: * AssetsDatabaseManager.initManager(getApplication()); // this method is only need call one time * AssetsDatabaseManager mg = AssetsDatabaseManager.getManager(); // get a AssetsDatabaseManager object * SQLiteDatabase db1 = mg.getDatabase("db1.db"); // get SQLiteDatabase object, db1.db is a file in assets folder * db1.??? // every operate by you want * Of cause, you can use AssetsDatabaseManager.getManager().getDatabase("xx") to get a database when you need use a database */
public class AssetsDatabaseManager { private static String tag = "AssetsDatabase"; // for LogCat private static String databasepath = "/data/data/%s/databases"; // %s is packageName // A mapping from assets database file to SQLiteDatabase object private Map<String, SQLiteDatabase> databases = new HashMap<String, SQLiteDatabase>(); // Context of application private Context context = null; // Singleton Pattern private static AssetsDatabaseManager mInstance = null; /** * Initialize AssetsDatabaseManager * @param context, context of application */ public static void initManager(Context context){ if(mInstance == null){ mInstance = new AssetsDatabaseManager(context); } } /** * Get a AssetsDatabaseManager object * @return, if success return a AssetsDatabaseManager object, else return null */ public static AssetsDatabaseManager getManager(){ return mInstance; } private AssetsDatabaseManager(Context context){ this.context = context; } /** * Get a assets database, if this database is opened this method is only return a copy of the opened database * @param dbfile, the assets file which will be opened for a database * @return, if success it return a SQLiteDatabase object else return null */ public SQLiteDatabase getDatabase(String dbfile) { if(databases.get(dbfile) != null){ Log.i(tag, String.format("Return a database copy of %s", dbfile)); return (SQLiteDatabase) databases.get(dbfile); } if(context==null) return null; Log.i(tag, String.format("Create database %s", dbfile)); String spath = getDatabaseFilepath(); String sfile = getDatabaseFile(dbfile); File file = new File(sfile); SharedPreferences dbs = context.getSharedPreferences(AssetsDatabaseManager.class.toString(), 0); boolean flag = dbs.getBoolean(dbfile, false); // Get Database file flag, if true means this database file was copied and valid if(!flag || !file.exists()){ file = new File(spath); if(!file.exists() && !file.mkdirs()){ Log.i(tag, "Create \""+spath+"\" fail!"); return null; } if(!copyAssetsToFilesystem(dbfile, sfile)){ Log.i(tag, String.format("Copy %s to %s fail!", dbfile, sfile)); return null; } dbs.edit().putBoolean(dbfile, true).commit(); } SQLiteDatabase db = SQLiteDatabase.openDatabase(sfile, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); if(db != null){ databases.put(dbfile, db); } return db; } private String getDatabaseFilepath(){ return String.format(databasepath, context.getApplicationInfo().packageName); } private String getDatabaseFile(String dbfile){ return getDatabaseFilepath()+"/"+dbfile; } private boolean copyAssetsToFilesystem(String assetsSrc, String des){ Log.i(tag, "Copy "+assetsSrc+" to "+des); InputStream istream = null; OutputStream ostream = null; try{ AssetManager am = context.getAssets(); istream = am.open(assetsSrc); ostream = new FileOutputStream(des); byte[] buffer = new byte[1024]; int length; while ((length = istream.read(buffer))>0){ ostream.write(buffer, 0, length); } istream.close(); ostream.close(); } catch(Exception e){ e.printStackTrace(); try{ if(istream!=null) istream.close(); if(ostream!=null) ostream.close(); } catch(Exception ee){ ee.printStackTrace(); } return false; } return true; } /** * Close assets database * @param dbfile, the assets file which will be closed soon * @return, the status of this operating */ public boolean closeDatabase(String dbfile){ if(databases.get(dbfile) != null){ SQLiteDatabase db = (SQLiteDatabase) databases.get(dbfile); db.close(); databases.remove(dbfile); return true; } return false; } /** * Close all assets database */ static public void closeAllDatabase(){ Log.i(tag, "closeAllDatabase"); if(mInstance != null){ for(int i=0; i<mInstance.databases.size(); ++i){ if(mInstance.databases.get(i)!=null){ mInstance.databases.get(i).close(); } } mInstance.databases.clear(); } } }
package db;

import android.app.Application;
import android.database.sqlite.SQLiteDatabase;

public class DBManager {

    public static SQLiteDatabase getdb(Application mApplication) {
        // 初始化,只需要呼叫一次
        AssetsDatabaseManager.initManager(mApplication);
        // 獲取管理物件,因為資料庫需要通過管理物件才能夠獲取
        AssetsDatabaseManager mg = AssetsDatabaseManager.getManager();
        // 通過管理物件獲取資料庫
        SQLiteDatabase db = mg.getDatabase("china_citys_name.sqlite");
        return db;
    }

}

2、這裡的資料提取需要注意要嚴格區分層級關係。其實就是你要模擬佔位你的父級元素的個數,因為後面是通過ArrayList的position提取的。這個作者沒講清楚,我也沒時間做進一步封裝,因為主體原始碼都是作者的,不好意思提煉出來做二次封裝。我debug模式下,貼幾張圖,給大夥感受下:

如果你報了這個錯誤,就好好用心感受下,這7張圖。。。血的教訓
ArrayList陣列越界

java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1

1、3個數據最外層的size必須一致

這裡寫圖片描述

2、省份就一層資料
這裡寫圖片描述
3、城市需要先外部巢狀一層省份

這裡寫圖片描述
4、第二層list中的才是每個省份所對應的城市
這裡寫圖片描述
5、區域最外層(跟省份size一致)
這裡寫圖片描述
6、區域第二層(跟對應省份的對應城市的size一致)
這裡寫圖片描述
7、區域第三層(跟對應省份的對應城市的對應區域的size)
這裡寫圖片描述

8、主要原因是因為,提取顯示的時候是嚴格按照list下的position來獲取的,所以一切都清楚了

 //返回的分別是三個級別的選中位置
                String tx = options1Items.get(options1).getPro_name()
                        + options2Items.get(options1).get(option2).getName()
                        + options3Items.get(options1).get(option2).get(options3).getName();

3、初始化OptionsPickerView,並使用

MainActivity.java

package com.pickerview.pickerviewdemo;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.bigkoo.pickerview.OptionsPickerView;

import java.util.ArrayList;

import db.AreaBean;
import db.CityBean;
import db.DBManager;
import db.ProvinceBean;

public class MainActivity extends AppCompatActivity {

    private TextView tvTitle;
    private OptionsPickerView pvOptions;//地址選擇器
    private ArrayList<ProvinceBean> options1Items = new ArrayList<>();//省
    private ArrayList<ArrayList<CityBean>> options2Items = new ArrayList<>();//市
    private ArrayList<ArrayList<ArrayList<AreaBean>>> options3Items = new ArrayList<>();//區
    private ArrayList<String> Provincestr = new ArrayList<>();//省
    private ArrayList<ArrayList<String>> Citystr = new ArrayList<>();//市
    private ArrayList<ArrayList<ArrayList<String>>> Areastr = new ArrayList<>();//區

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initEvent();
    }

    private void initView() {
        tvTitle = (TextView) findViewById(R.id.tvTitle);
    }

    private void initData() {
        //選項選擇器
        pvOptions = new OptionsPickerView(this);
        // 獲取資料庫
        SQLiteDatabase db = DBManager.getdb(getApplication());
        //省
        Cursor cursor = db.query("province", null, null, null, null, null,
                null);
        while (cursor.moveToNext()) {
            int pro_id = cursor.getInt(0);
            String pro_code = cursor.getString(1);
            String pro_name = cursor.getString(2);
            String pro_name2 = cursor.getString(3);
            ProvinceBean provinceBean = new ProvinceBean(pro_id, pro_code, pro_name, pro_name2);
            options1Items.add(provinceBean);//新增一級目錄
            Provincestr.add(cursor.getString(2));
            //查詢二級目錄,市區
            Cursor cursor1 = db.query("city", null, "province_id=?", new String[]{pro_id + ""}, null, null,
                    null);
            ArrayList<CityBean> cityBeanList = new ArrayList<>();
            ArrayList<String> cityStr = new ArrayList<>();
            //地區集合的集合(注意這裡要的是當前省份下面,當前所有城市的地區集合我去)
            ArrayList<ArrayList<AreaBean>> options3Items_03 = new ArrayList<>();
            ArrayList<ArrayList<String>> options3Items_str = new ArrayList<>();
            while (cursor1.moveToNext()) {
                int cityid = cursor1.getInt(0);
                int province_id = cursor1.getInt(1);
                String code = cursor1.getString(2);
                String name = cursor1.getString(3);
                String provincecode = cursor1.getString(4);
                CityBean cityBean = new CityBean(cityid, province_id, code, name, provincecode);
                //新增二級目錄
                cityBeanList.add(cityBean);
                cityStr.add(cursor1.getString(3));
                //查詢三級目錄
                Cursor cursor2 = db.query("area", null, "city_id=?", new String[]{cityid + ""}, null, null,
                        null);
                ArrayList<AreaBean> areaBeanList = new ArrayList<>();
                ArrayList<String> areaBeanstr = new ArrayList<>();
                while (cursor2.moveToNext()) {
                    int areaid = cursor2.getInt(0);
                    int city_id = cursor2.getInt(1);
//                    String code0=cursor2.getString(2);
                    String areaname = cursor2.getString(3);
                    String citycode = cursor2.getString(4);
                    AreaBean areaBean = new AreaBean(areaid, city_id, areaname, citycode);
                    areaBeanList.add(areaBean);
                    areaBeanstr.add(cursor2.getString(3));
                }
                options3Items_str.add(areaBeanstr);//本次查詢的儲存內容
                options3Items_03.add(areaBeanList);
            }
            options2Items.add(cityBeanList);//增加二級目錄資料
            Citystr.add(cityStr);
            options3Items.add(options3Items_03);//新增三級目錄
            Areastr.add(options3Items_str);
        }
        //設定三級聯動效果
        pvOptions.setPicker(Provincestr, Citystr, Areastr, true);
        //設定選擇的三級單位
//        pvOptions.setLabels("省", "市", "區");
        pvOptions.setTitle("選擇城市");
        //設定是否迴圈滾動
        pvOptions.setCyclic(false, false, false);
        //設定預設選中的三級專案
        //監聽確定選擇按鈕
        pvOptions.setSelectOptions(0, 0, 0);
        pvOptions.setOnoptionsSelectListener(new OptionsPickerView.OnOptionsSelectListener() {
            @Override
            public void onOptionsSelect(int options1, int option2, int options3) {
                //返回的分別是三個級別的選中位置
                String tx = options1Items.get(options1).getPro_name()
                        + options2Items.get(options1).get(option2).getName()
                        + options3Items.get(options1).get(option2).get(options3).getName();
                tvTitle.setText(tx);
            }
        });
    }

    private void initEvent() {
        tvTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pvOptions.show();
            }
        });
    }
}

4、xml檔案就不貼了,就是一個Hellow World的標籤

看下這個demo的執行效果圖:
這裡寫圖片描述

總結:等有空還是要完善下的。希望我的這些坑對你有一點點的幫助,have a nice day~

相關推薦

使用Android-PickerView實現地址選擇時間選擇

這裡貢獻下我使用Android-PickerView實現地址選擇器遇到的坑,算是一個筆記。首先要吐槽下後臺介面,為了實現移動端和web端的統一(ps:可能他沒搞過後臺介面),修改地址的時候本來要用下拉框。。。我去,後面ios的大兄弟苦苦哀求,改成了他們io

Android簡單實現本地圖片和視訊選擇功能

哈嘍,大家好,好久不見了,很久沒有更新 Android 方面的技術文章了,最近在忙公司的 AR 類的新產品,其中涉及到本地圖片和視訊的選擇和上傳功能。至於為什麼不用系統提供的圖片和視訊選擇器,原因你懂的,系統提供的選擇器只能通過 Intent 方式去獲取,這意味

Android TimePickerDialog(原生安卓時間選擇

這個控制元件說實話之前沒用過原生的,都是用的自定義的,其實這個也挺好看的。 public class MainActivity extends AppCompatActivity { private Calendar c; @Override prot

組裝原有控制元件實現橫向滾動的時間選擇,可滑動 點選,初始狀態在指定位置

簡介 前段時間,產品設計了一個橫向的滾動的時間選擇器,由於工作很急,也沒時間來自定義view,而且目前開發的專案很老了,不支援V7的包,所以我不能用recyclerview。我就將就之前的GridView和HorizontalScrollView,組裝了一哈就可以了。本

【ElementUI】日期選擇時間選擇範圍限制

del this 以及 ui框架 .get led () 設置 ons   ElementUI是餓了麽推出的一套基於vue2.x的一個ui框架。官方文檔也很詳細,這裏做一個element-ui日期插件的補充。   官方文檔中使用picker-options屬性來限制可選擇的

ElementUI日期選擇時間選擇範圍限制

date ron let 推出 舉例 strong 2.x ons 餓了麽   ElementUI是餓了麽推出的一套基於vue2.x的一個ui框架。官方文檔也很詳細,這裏做一個element-ui日期插件的補充,官方文檔中使用picker-options屬性來限制可選擇的日

【ElementUI】日期選擇時間選擇範圍限制,只能選今天之前的時間,或者是隻能選今天之後的時間。今天是否可以選

<el-date-picker v-model="value1" type="date" placeholder="選擇日期" :picker-options="pickerOptions0"> </el-date-picke

微信小程式自定義元件實現地址單級連續選擇(拼多多APP地址選擇樣式)

最終效果在 首先在page資料夾下建立components資料夾,在components資料夾下建立region-picker的資料夾,然後在region-picker資料夾下建立Component名稱為region-picker。 region-picke

國內互聯網可用時間服務地址(NTP時間服務地址

NTP 時間服務器 老男孩教育 老男孩老師在教學培訓過程中經常發現曾經的時間服務器地址不可用了,很是尷尬,特找到了國內比較穩定的時間服務器地址,和博友分享如下:ntp1.aliyun.com ntp2.aliyun.com ntp3.aliyun.com ntp4.aliyun.com ntp5

Android實現一個簡易的Http服務

.get json data ESS public 瀏覽器 顯示 getmethod blank 最近遇到一個需求需要在App中創建一個Http服務器供供瀏覽器調用,用了下開源的微型Htpp服務器框架:NanoHttpd,項目地址:https://github.com/Na

easyUI自帶的時間外掛日期選擇、月份選擇時間選擇的使用

1.日期選擇    只要將class設定成easyui-datebox就可以了,當然前提是已經應用了easyui的js <input type="text" class="easyui-datebox" id="datetime">  2.時間選擇 預設的時

UNIX 獲取服務時間服務程序

監聽描述符#include "unp.h" #include <time.h> int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_in servaddr; char

時間選擇Android-PickerView的使用

GitHub Android-PickerView絕不僅僅只能實現時間選擇,還能實現省市區等聯動效果,更多使用請戳→GitHub 時間選擇器效果圖 先用起來 新增依賴 compile 'com.contrarywind:Android-PickerView:4.

Android 時間選擇 PickerView,的詳細使用

private void initTimePicker1() {//選擇出生年月日 //控制時間範圍(如果不設定範圍,則使用預設時間1900-2100年,此段程式碼可註釋) //因為系統Calendar的月份是從0-11的,所以如果是呼叫Calendar的set方法來設定時

使用pickerview實現(省市區)地址選擇的三級聯動

此三級聯動的實現基於pickerview,附上github地址:Android-PickerView 這是一款仿iOS的PickerView控制元件,有時間選擇和選項選擇,並支援一二三級聯動,支援自定義樣式。 首先下載pickerview,將其作為Module新增進你的

Android零基礎入門第57節:日期選擇DatePicker和時間選擇TimePicker

oncreate ted show imageview bce min date 教程 運行程序 在實際開發中,經常會遇見一些時間選擇器、日期選擇器、數字選擇器等需求,那麽從本期開始來學習Android中常用選擇器,今天學習的是DatePicker和TimePicke

android日期時間選擇

net oid androi class 我們 下載地址 很好 需要 滿足 android原生的日期時間控件,因為是原生的總有其滿足不了我們需求的時候,Android 手機版本那麽多,用戶彈出來的控件五花八門。因為項目需要,在網上找了一 些demo看了看,感覺有些寫的很好,

[Android開發基礎] 時間選擇

佈局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_w

PickerView的使用(時間選擇

前段時間,因業務整合,有個需求是把原來可以選擇年月日的彈窗改為僅選擇年月。 前期思路 重寫原生的DatePickerDialog,設定DatePickerDialog的樣式為年月日為滑動選擇,隱藏日的選擇,實現功能。 程式碼如下: import android.app

Android自定義帶有聯動時間選擇(年,月,日,周,十,分)備錄

概述:         在日常的android開發中經常會遇到關於時間選擇的操作開發,比如和賬單記錄有關的記賬類軟體,以及進行鬧鐘定時任務的定時類軟體扥等。實現時間選擇器往往都會用到android.widget包中的NumPicker控制元件。關於NumPick