动态获取数据级联android_更新element 级联选择器动态获取数据 点击一级触发二级 - CSDN
  • package org.jian.database;...import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBHelper extends SQLiteOpenHel

    以前学习Java EE的时候,经常会遇到一些下拉表单进行联动的实例。

    例子:假如一个公司有三个部门,括号里面是职位

    人力资源部(员工关系主管,招聘主管 )

    财务部(财务总监、财务部经理、审计主管)

    生产技术部(程序员,设计师,架构师)


    我们将做个两级联动的spinner,当我第一级选择不同的部门,第二级将显示不同的职位


    SQLiteOpenHelper类:

    package org.jian.database;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class DBHelper extends SQLiteOpenHelper {
        private static final String DB_NAME = "martin.db" ;
        private static final int VERSION = 3 ;
        
        SQLiteDatabase db ;
        private String job_sql = "CREATE TABLE IF NOT EXISTS job(" +
                                 "_id INTEGER PRIMARY KEY ," +
                                 "jobname VARCHAR(20) ," +
                                 "did INTEGER" +
                                 ")" ;
        private String dept_sql = "CREATE TABLE IF NOT EXISTS dept(" +
                                  "_id INTEGER PRIMARY KEY ," +
                                  "deptname VARCHAR(20)" +
                                  ")" ;
        
        public DBHelper(Context context) {
            super(context, DB_NAME, null, VERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            this.db = db ;
            db.execSQL(job_sql) ;
            db.execSQL(dept_sql) ;
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            
        }
    
    }
    
    
    
    

    用sql插入数据(在sqlite里,用adb进入):

    INSERT INTO job VALUES(null ,"员工关系主管" , 1) ;
    INSERT INTO job VALUES(null ,"招聘主管 " , 1) ;
    INSERT INTO job VALUES(null ,"财务总监" , 2) ;
    INSERT INTO job VALUES(null ,"财务部经理" , 2) ;
    INSERT INTO job VALUES(null ,"审计主管" , 2) ;
    INSERT INTO job VALUES(null ,"程序员" , 3) ;
    INSERT INTO job VALUES(null ,"设计师" , 3) ;
    INSERT INTO job VALUES(null ,"架构师" , 3) ;
    
    INSERT INTO dept VALUES(null ,"人力资源部" ) ;
    INSERT INTO dept VALUES(null ,"财务部" ) ;
    INSERT INTO dept VALUES(null ,"生产技术部" ) ;
    

    处理数据的类:

    package org.jian.service;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.jian.database.DBHelper;
    
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    
    public class Database {
        private DBHelper dbHelper;
    
        public Database(Context context) {
            dbHelper = new DBHelper(context);
        }
    
        /**
         * 查询数据库,返回一个Map 这个Map包括 1,spinner需要显示的字符串,以及其所组成的map 2,spinner需要显示的字符串
         * 
         * @return
         */
        public Map<Integer, List<?>> getDepts() {
            String sql = "SELECT _id, deptname FROM dept";   //获取部门Id号与部门的名称
            SQLiteDatabase db = null;
            Cursor c = null;
            Map<Integer, List<?>> DeptData = new HashMap<Integer, List<?>>();
            try {
                db = dbHelper.getWritableDatabase(); // 获取数据库
                c = db.rawQuery(sql, null);
                List<Map<String, Integer>> collegeList1 = new ArrayList<Map<String, Integer>>();
                List<String> collegeList2 = new ArrayList<String>();
                while (c.moveToNext()) {
                    Map<String, Integer> provinceMap = new HashMap<String, Integer>(); // 这个HashMap主要是用来白村学院的信息以及他的id
                    String name = new String(c.getBlob(1), "GBK");
                    provinceMap.put(name, c.getInt(0));
                    collegeList1.add(provinceMap); // 保存这个Map
                    collegeList2.add(name); // 保存这个名字的列表
                }
                DeptData.put(0, collegeList1);
                DeptData.put(1, collegeList2);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (c != null) {
                    c.close();
                }
                if (db != null) {
                    db.close();
                }
            }
            return DeptData;
        }
    
        /**
         * 返回一个List
         * 包含job的字符串所组成的数组
         * @param id
         * @return
         */
        public List<String> getJobById(int id) {
            String sql = "SELECT jobname FROM job WHERE did = " + id;
            SQLiteDatabase db = null;
            Cursor c = null;
            List<String> jobList = null;
            try {
                db = dbHelper.getWritableDatabase();
                c = db.rawQuery(sql, null);
                jobList = new ArrayList<String>();
                while (c.moveToNext()) {
                    String jobName = new String(c.getBlob(0),"GBK") ;  //解决乱码
                    jobList.add(jobName);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                if (c != null) {
                    c.close();
                }
                if (db != null) {
                    db.close();
                }
            }
            return jobList;
    
        }
    }



    界面设计XML:spinner.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="请选择你的部门" />
    
        <Spinner
            android:id="@+id/dept"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="请选择你的职位" />
    
        <Spinner
            android:id="@+id/job"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>



    Activity类:

    package org.jian.activity;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.jian.service.Database;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemSelectedListener;
    import android.widget.ArrayAdapter;
    import android.widget.Spinner;
    
    import com.example.spinner.R;
    
    public class MainActivity extends Activity {
        List deptList = new ArrayList();
    
        List deptData = new ArrayList();
    
        List jobList = new ArrayList();
       
        Spinner job;
        Spinner dept;
        Database db;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.spanner);
            job = (Spinner) findViewById(R.id.job);
            dept = (Spinner) findViewById(R.id.dept);
            db = new Database(getApplicationContext());
    
            Map<Integer, List<?>> data = database.getDepts();// 得到数据库数据
    
            deptList = data.get(1);
            deptData = data.get(0);
    
            ArrayAdapter deptAdapter = new ArrayAdapter(MainActivity.this,
                    android.R.layout.simple_spinner_item, deptList);
            deptAdapter
                    .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // 样式
    
            dept.setAdapter(deptAdapter);
    
            dept.setOnItemSelectedListener(itemSelectedListener);
        }
    
        private OnItemSelectedListener itemSelectedListener = new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view,
                    int position, long id) {
                Spinner spdept = (Spinner) parent;
                String seldept = (String) spdept.getItemAtPosition(position);
                ArrayAdapter jobAdapter = null;
                Map<String, Integer> data = (Map<String, Integer>) deptData
                        .get(position);// 根据id,返回本门号的信息
    
                int pid = data.get(seldept);// 得到部门号的id
                List<String> jobList = db.getJobById(pid); // 根据id查得工作类型的一个List
    
                jobAdapter = new ArrayAdapter(MainActivity.this,
                        android.R.layout.simple_spinner_item, jobList);
                jobAdapter
                        .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                job.setAdapter(jobAdapter);
                job.setOnItemSelectedListener(jobSelectedListener);
    
            }
    
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        };
    
        String selectedJob = null;
        private OnItemSelectedListener jobSelectedListener = new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view,
                    int position, long id) {
                Spinner spjob = (Spinner) parent;
                selectedJob = (String) spjob.getItemAtPosition(position);
    
            }
    
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
    
            }
        };
    
    }
    
    
    

    运行结果:

    当我选择部门为:财务部时:

    工作职位出现的为:



    展开全文
  • 关于Android移动端多级列表(超过两)的几种实现方式,包含静态(展示前已能获取全部数据)和动态(子数据需点击父数据获取)两种形式

    通常这种多级列表更多见于web端,移动端常见为省份选择之类的情况(类似QQ分组的通常只有两级),由于手机屏幕的限制,相当一部分也选择多个页面显示,所以也许用得不是很多,但俗话说,只有想不到的需求,没有不被要求到的需求,所以吐舌头以防万一吧……

    首先,最常见的为类似于省市这种形式的列表,特征是在展示前你可以获得全部数据,包括子列表,这也是最常见的多级列表形式。谷歌官方有提供ExpandableListView,可以实现两级列表,我个人以为,也这表明谷歌本身也只推荐手机端只实现两级的缩进(纯吐槽:坦白说以手机屏幕的宽度来看,在同一页面通过缩进来显示两级以上多级的层级关系真是毫无美感可言)。多级列表网上有一些实现方式,主要是前两种,都是展示前可以获得全部数据的,第三种是动态获取子列表数据时的实现方式,如下:


    第一种方式:以单个listView实现,纯粹依赖缩进来造成层级效果

    这种实现方式实质是以一个ListView列表来实现,无论是子列表数据还是父列表数据,展示时实际是处于同一级的,只是通过给子数据添加缩进,人为的制造出层级关系,看起来像是多级列表而已。取根列表数据资源存于代码中的firstLayerList列表,全部列表数据资源于totalList列表,但列表中每一项并不是直接的数据资源,而是数据本身、层级、数据本身id、数据父id、是否有子数据、是否已展开的一个封装对象。如:列表为List<Data>,数据为Data(String dataStr,int layer,long dataId,long dataParentId,boolean hasSubDatas,boolean isExpand);

    在getView()方法中注意两点,一是根据子列表的层级计算并添加缩进,二是注意可见性,因为在convertView复用过程中有可能会复用可见性与当前项不同的view。

    然后就是OnItemClickListener()方法,分三种情况:

    • 若是点击项无子数据,点击不响应,return。
    • 若是点击项有子数据并已展开,则响应为隐藏子数据,具体实现方式为从当前项下一项开始,以当前列表总项数为上限循环,对当前项之后的每一项作层级判断,如果layer值大于当前点击的position项的layer值,则说明为当前项的子数据、子子数据、子子子数据等,一直遍历到某一项layer值小于或等于当前选中position项的layerw值时break出循环,将遍历到的这些数据存入toDelList列表,然后通过removeAll(...)从当前列表的数据列表firstLayerList中移除toDelList列表中的所有数据项,调用notifyDataSetChanged()方法刷新列表。
    • 若是点击项有子数据但未展开,则响应为展示子数据,具体实现方式为取当前点击项的dataId,遍历全部数据列表totalList,取每一项的dataParentId与当前点击项dataId比较,如果相等则说明为需要展示的子数据(当然,只是下一级子节点,好在需求也只是下一级),分别存入当前展示数据列表中的第position + i项,i从1开始累加,遍历完totalList列表后,刷新列表,会显示为展开子列表。
    第二种方式:通过修改ExpandableListView来实现

    这种方式虽可实现,但比较繁复,且ExpandableListView本身提供的一些方法又不能直接用了,不推荐。


    第三种,动态获取数据实现三级列表

    这种针对的是在展示之前无法获取到子数据的情况,就是必须点击父数据项才去请求子数据的情况。

    在我的示例里,拿到的作务列表中该任务数据中是包含有子任务数的,即下例中的getSubs()方法得到的b子任务数。

    公司项目,只能截取代码片段了,adapter,subAdapter,grandSubAdapter是同一类的不同对象实现。
        /**
         * 任务列表监听
         */
        private AdapterView.OnItemClickListener taskItemListener = new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (0 != ((Task) (mAdapter.getItem((int) id))).getSubs()) {//在没有表头的前提下,(int)id和position是一样的效果,只是个人习惯
                    subListView = (ListView) view.findViewById(R.id.sub_task_list);//在adapter的xml布局里,最下方包含一个<ListView ...../>,默认为隐藏状态View.GONE
                    //subListView.setAdapter(subAdapter);
                    if (View.VISIBLE == subListView.getVisibility()) {//当子listView可见时,说明是展开状态,点击时的响应就应该是关闭
                        subListView.setVisibility(View.GONE);
                    } else {//子listView不可见,则展开子列表
                        subListView.setVisibility(View.VISIBLE);
                        subListView.setFocusable(false);
                        subListView.setOnItemClickListener(subTaskItemListener);
                        
                requestSubListDatas(((Task)(mAdapter.getItem((int)id))).getId());//参数为当前任务项id,请求该任务的子任务数据
        //这里我是以Message形式传递给handler处理,为了便于阅读,就放在这里吧
       subAdapter.setmTasks(子任务列表数据);
       
       ViewGroup.LayoutParams parentLp = subListView.getLayoutParams();
       //这里可添加判断,只需计算一次即可
      measureView = subAdapter.getView(0,null,subListView);//measureView为一个View对象
      //注意在这里要求Adapter的布局文件中的listView控件的父容器为LinearLayout布局,否则会报错
      measureView.measure(0,0);
      parentLp.height = measureView.getMeasuredHeight() * subAdapter.getCount();
    subListView.setLayoutParams(parentLp);

    subListView.setAdapter(subAdapter);
                    }
                }
            }
        };


        /**
         * 子任务列表监听
         */
        private AdapterView.OnItemClickListener subTaskItemListener = new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View subView, int position, long subId) {
                if (0 != ((Task) (subAdapter.getItem((int) subId))).getSubs()) {
                    grandSubListView = (ListView) subView.findViewById(R.id.sub_task_list);
                    //grandSubListView.setAdapter(grandSubAdapter);
                    if (View.VISIBLE == grandSubListView.getVisibility()) {
                        grandSubListView.setVisibility(View.GONE);
                        //grandSubListView.setLayoutParams(subParentParams);
                        ViewGroup.LayoutParams mParentParams = subListView.getLayoutParams();
                        mParentParams.height -= grandSubListView.getLayoutParams().height;
                        subListView.setLayoutParams(mParentParams);
                    } else {
                        grandSubListView.setVisibility(View.VISIBLE);
                        grandSubListView.setFocusable(false);

                        //与以上任务列表监听相似,就不重复了

                    }
                }
            }
        };

    实现起来也不难,最主要是需在子列表展开前计算出子列表的高度以提供给子列表展示的空间。

    展开全文
  • Android实现省市区三联动效果

    万次阅读 多人点赞 2020-01-02 17:15:29
    最近在做项目时有一个选择省市区的三联动效果。百度上搜了好久也没找到一个合适的控件。后来再github上找到一个不错的三联动控件,拿来用发现效果还挺好。把自己写的一个demo分享一下。 控件名称为PickerView,...

    PickerView控件的作者在3.0版本中对PickerView源码进行了重构。重构后的PickerView添加了很多可自定义的属性,比如可以自定义文字颜色、大小等。使用也更加方便了。只是改动较大,使用方法也与2.0版本有不少差别。
    由于2.0版本时候作者没有给出详细的省市区三级联动的Demo。因此才有了这篇文章。现在3.0版本作者已经给出了很详细的例子。大家可以到作者的github下载Demo作参考:
    PickerView项目地址:https://github.com/saiwu-bigkoo/Android-PickerView

    最近在做项目时有一个选择省市区的三级联动效果。百度上搜了好久也没找到一个合适的控件。后来再github上找到一个不错的三级联动控件,拿来用发现效果还挺好。把自己写的一个demo分享一下。
    控件名称为PickerView,实现了 iOS 的 PickerView 的效果,并且有时间选择和选项选择还支持一二三级联动效果。
    PickerView项目地址:https://github.com/saiwu-bigkoo/Android-PickerView
    控件用起来非常简单,但在填充数据时稍微有些麻烦,我这里用的省市区数据为json格式,json数据就不贴出了,稍后会把源码上传。
    先看下效果图:
    这里写图片描述
    首先使用gradle 依赖

    
       compile 'com.bigkoo:pickerview:2.1.0'
    

    布局文件只有一个TextView

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.sensor.zhangpan.mypickerview.MainActivity">
    
        <TextView
            android:id="@+id/tv_address"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="点击选择地址"
            android:layout_centerInParent="true"
            android:textSize="20sp"/>
    </RelativeLayout>
    

    省份的实体类(控件的数据格式要求须有一个省份实体类)

    public class ProvinceBean {
        private String name;
    
    
        public ProvinceBean(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    
        /*这个用来显示在PickerView上面的字符串,PickerView会通过反射获
        取getPickerViewText方法显示出来。*/
        public String getPickerViewText() {
            //这里还可以判断文字超长截断再提供显示
            return this.name;
        }
    }
    

    下面这个类用来读取json数据,并将读取到的数据以String格式返回(json数据放在assets目录下,文件名为province_data.json)

    //  读取assets中的json文件
    public class JsonFileReader {
        public static String getJson(Context context, String fileName) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                AssetManager assetManager = context.getAssets();
                InputStream inputStream = assetManager.open(fileName);
                BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                byte[] buffer = new byte[1024];
                int len;
                while ((len = bufferedInputStream.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    baos.close();
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return baos.toString();
        }
    }
    

    MainActivity中的代码,注释写的非常详细,这里就不作太多解释了,详情看代码。

    public class MainActivity extends AppCompatActivity {
    
        private TextView mTextViewAddress;
    
        OptionsPickerView pvOptions;
        //  省份
        ArrayList<ProvinceBean> provinceBeanList = new ArrayList<>();
        //  城市
        ArrayList<String> cities;
        ArrayList<List<String>> cityList = new ArrayList<>();
        //  区/县
        ArrayList<String> district;
        ArrayList<List<String>> districts;
        ArrayList<List<List<String>>> districtList = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //  创建选项选择器
            pvOptions = new OptionsPickerView(this);
            mTextViewAddress = (TextView) findViewById(R.id.tv_address);
    
            //  获取json数据
            String province_data_json = JsonFileReader.getJson(this, "province_data.json");
            //  解析json数据
            parseJson(province_data_json);
    
            //  设置三级联动效果
            pvOptions.setPicker(provinceBeanList, cityList, districtList, 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 city = provinceBeanList.get(options1).getPickerViewText();
                    String address;
                    //  如果是直辖市或者特别行政区只设置市和区/县
                    if ("北京市".equals(city) || "上海市".equals(city) || "天津市".equals(city) || "重庆市".equals(city) || "澳门".equals(city) || "香港".equals(city)) {
                        address = provinceBeanList.get(options1).getPickerViewText()
                                + " " + districtList.get(options1).get(option2).get(options3);
                    } else {
                        address = provinceBeanList.get(options1).getPickerViewText()
                                + " " + cityList.get(options1).get(option2)
                                + " " + districtList.get(options1).get(option2).get(options3);
                    }
                    mTextViewAddress.setText(address);
                }
            });
    
    
            //  点击弹出选项选择器
            mTextViewAddress.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    pvOptions.show();
                }
            });
        }
    
        //  解析json填充集合
        public void parseJson(String str) {
            try {
                //  获取json中的数组
                JSONArray jsonArray = new JSONArray(str);
                //  遍历数据组
                for (int i = 0; i < jsonArray.length(); i++) {
                    //  获取省份的对象
                    JSONObject provinceObject = jsonArray.optJSONObject(i);
                    //  获取省份名称放入集合
                    String provinceName = provinceObject.getString("name");
                    provinceBeanList.add(new ProvinceBean(provinceName));
                    //  获取城市数组
                    JSONArray cityArray = provinceObject.optJSONArray("city");
                    cities = new ArrayList<>();//   声明存放城市的集合
                    districts = new ArrayList<>();//声明存放区县集合的集合
                    //  遍历城市数组
                    for (int j = 0; j < cityArray.length(); j++) {
                        //  获取城市对象
                        JSONObject cityObject = cityArray.optJSONObject(j);
                        //  将城市放入集合
                        String cityName = cityObject.optString("name");
                        cities.add(cityName);
                        district = new ArrayList<>();// 声明存放区县的集合
                        //  获取区县的数组
                        JSONArray areaArray = cityObject.optJSONArray("area");
                        //  遍历区县数组,获取到区县名称并放入集合
                        for (int k = 0; k < areaArray.length(); k++) {
                            String areaName = areaArray.getString(k);
                            district.add(areaName);
                        }
                        //  将区县的集合放入集合
                        districts.add(district);
                    }
                    //  将存放区县集合的集合放入集合
                    districtList.add(districts);
                    //  将存放城市的集合放入集合
                    cityList.add(cities);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }
    

    就这么简单一个三级联动效果就实现了。
    修改字体大小及颜色可以参看这篇文章:Android-PickerView 三级联动选择器的标题和内容的字体大小、颜色设置

    好库推荐

    给大家推荐一下BannerViewPager。这是一个基于ViewPager实现的具有强大功能的无限轮播库。通过BannerViewPager可以实现腾讯视频、QQ音乐、酷狗音乐、支付宝、天猫、淘宝、优酷视频、喜马拉雅、网易云音乐、哔哩哔哩等APP的Banner样式以及指示器样式。

    欢迎大家到github关注BannerViewPager

    展开全文
  • Android实现省市区三联动

    千次阅读 热门讨论 2018-09-06 17:01:18
    最近做项目时,有个需求是在用户填写的个人资料中有个选择省市区的三联动效果,通过一番查找,在github上找到一个不错的控件:PickerView。 github项目地址为:https://github.com/Bigkoo/Android-PickerView ...

    最近做项目时,有个需求是在用户填写的个人资料中有个选择省市区的三级联动效果,通过一番查找,在github上找到一个不错的控件:PickerView。

    github项目地址为:https://github.com/Bigkoo/Android-PickerView
    控件使用起来非常简单,先上效果图:

    使用PickerView前首先要添加依赖:

     compile 'com.contrarywind:Android-PickerView:4.1.6'

    布局文件也非常简单,可以根据需求更换View:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.a34413.pickerviewdemo.MainActivity">
    
        <TextView
            android:id="@+id/tv_address"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="选择地址"
            android:layout_centerInParent="true" />
    
    </RelativeLayout>

    因为控件的数据格式必须要一个实体类:

    public class JsonBean implements IPickerViewData {
    
        private String name;
        private List<CityBean> city;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<CityBean> getCityList() {
            return city;
        }
    
        public void setCityList(List<CityBean> city) {
            this.city = city;
        }
    
        // 实现 IPickerViewData 接口,
        // 这个用来显示在PickerView上面的字符串,
        // PickerView会通过IPickerViewData获取getPickerViewText方法显示出来。
        @Override
        public String getPickerViewText() {
            return this.name;
        }
    
    
        public static class CityBean {
           
            private String name;
            private List<String> area;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public List<String> getArea() {
                return area;
            }
    
            public void setArea(List<String> area) {
                this.area = area;
            }
        }
    }

    因为这里的json数据是放在assets文件夹下的.json文件,所以需要创建一个类用来读取json数据:

    public class GetJsonDataUtil {
    
    
        public String getJson(Context context, String fileName) {
    
            StringBuilder stringBuilder = new StringBuilder();
            try {
                AssetManager assetManager = context.getAssets();
                BufferedReader bf = new BufferedReader(new InputStreamReader(
                        assetManager.open(fileName)));
                String line;
                while ((line = bf.readLine()) != null) {
                    stringBuilder.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return stringBuilder.toString();
        }
    }

    接下来上MainActivity,注释已经非常清楚,就不做过多解释:

    public class MainActivity extends Activity {
    
        private TextView mTvAddress;
        private ArrayList<JsonBean> options1Items = new ArrayList<>(); //省
        private ArrayList<ArrayList<String>> options2Items = new ArrayList<>();//市
        private ArrayList<ArrayList<ArrayList<String>>> options3Items = new ArrayList<>();//区
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mTvAddress = (TextView) findViewById(R.id.tv_address);
            initJsonData();
            mTvAddress.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    showPickerView();
                }
            });
        }
    
        private void showPickerView() {// 弹出选择器(省市区三级联动)
            OptionsPickerView pvOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
                @Override
                public void onOptionsSelect(int options1, int options2, int options3, View v) {
                    //返回的分别是三个级别的选中位置
                    mTvAddress.setText(options1Items.get(options1).getPickerViewText() + "  "
                            + options2Items.get(options1).get(options2) + "  "
                            + options3Items.get(options1).get(options2).get(options3));
    
                }
            })
                    .setTitleText("城市选择")
                    .setDividerColor(Color.BLACK)
                    .setTextColorCenter(Color.BLACK) //设置选中项文字颜色
                    .setContentTextSize(20)
                    .build();
            /*pvOptions.setPicker(options1Items);//一级选择器
            pvOptions.setPicker(options1Items, options2Items);//二级选择器*/
            pvOptions.setPicker(options1Items, options2Items, options3Items);//三级选择器
            pvOptions.show();
        }
    
    
        private void initJsonData() {//解析数据 (省市区三级联动)
            /**
             * 注意:assets 目录下的Json文件仅供参考,实际使用可自行替换文件
             * 关键逻辑在于循环体
             *
             * */
            String JsonData = new GetJsonDataUtil().getJson(this, "province.json");//获取assets目录下的json文件数据
    
            ArrayList<JsonBean> jsonBean = parseData(JsonData);//用Gson 转成实体
    
            /**
             * 添加省份数据
             *
             * 注意:如果是添加的JavaBean实体,则实体类需要实现 IPickerViewData 接口,
             * PickerView会通过getPickerViewText方法获取字符串显示出来。
             */
            options1Items = jsonBean;
    
            for (int i = 0; i < jsonBean.size(); i++) {//遍历省份
                ArrayList<String> CityList = new ArrayList<>();//该省的城市列表(第二级)
                ArrayList<ArrayList<String>> Province_AreaList = new ArrayList<>();//该省的所有地区列表(第三级)
    
                for (int c = 0; c < jsonBean.get(i).getCityList().size(); c++) {//遍历该省份的所有城市
                    String CityName = jsonBean.get(i).getCityList().get(c).getName();
                    CityList.add(CityName);//添加城市
                    ArrayList<String> City_AreaList = new ArrayList<>();//该城市的所有地区列表
    
                    //如果无地区数据,建议添加空字符串,防止数据为null 导致三个选项长度不匹配造成崩溃
                    if (jsonBean.get(i).getCityList().get(c).getArea() == null
                            || jsonBean.get(i).getCityList().get(c).getArea().size() == 0) {
                        City_AreaList.add("");
                    } else {
                        City_AreaList.addAll(jsonBean.get(i).getCityList().get(c).getArea());
                    }
                    Province_AreaList.add(City_AreaList);//添加该省所有地区数据
                }
    
                /**
                 * 添加城市数据
                 */
                options2Items.add(CityList);
    
                /**
                 * 添加地区数据
                 */
                options3Items.add(Province_AreaList);
            }
        }
    
        public ArrayList<JsonBean> parseData(String result) {//Gson 解析
            ArrayList<JsonBean> detail = new ArrayList<>();
            try {
                JSONArray data = new JSONArray(result);
                Gson gson = new Gson();
                for (int i = 0; i < data.length(); i++) {
                    JsonBean entity = gson.fromJson(data.optJSONObject(i).toString(), JsonBean.class);
                    detail.add(entity);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return detail;
        }
    }

    accets文件夹下的 .json文件可以直接去PickerView 的项目地址去拿,下面放上地址(文件名:province.json):

    https://github.com/Bigkoo/Android-PickerView/tree/master/app/src/main/assets

    如此一来一个简单的省市区多级联动就完成了~

    展开全文
  • android地区三联动选择

    千次阅读 2016-12-10 19:15:47
    地区三联动选择 一个Activity 2个Fragment, 在Activity中一次添加Fragment显示省级、市级、县级的列表。 Activity 根布局为FrameLayout,其中显示一个省级的RecyclerView的列表,在第一个省级列表RecyclerView的...
  • Android中省市区的三联动Android-wheel

    千次阅读 2016-11-10 13:13:10
    在项目开发中或多或少都会遇到地址的选择如淘宝,美团等。在ios中有PickerView可以很轻松的实现地区之间的轮滑和级联,在Android中,并没有可以直接实现此功能的控件,为了实现功能和...是一个非常好用的组件,对于数据
  • 言回正传,前些日子,女友在面试的过程中,面试官问:如何实现省市区三联动效果?这里记录下相关实现效果的学习过程,先上效果图: 准备步骤1、:android-wheel控件 如图看出,实现的效果类似于Android中...
  • 最新Android简单实现省市区三联动

    千次阅读 2019-03-23 23:26:08
    这是本人第一次写博客,也是本人的第一篇博客 ...我在网上看了很多篇关于Android省市区三联动的文章 感觉都说得不是很好,所以就打算自己写一篇,希望可以帮助到大家学习 废话不多说,进入正题 首先我用到的是 ...
  • android 省市区三联动选择器

    千次阅读 2018-06-26 15:59:23
    通过读取本地json文件显示数据,使用gson解析。 gradle中添加 //gson compile ‘com.google.code.gson:gson:2.1’ //滚动选择器 compile ‘com.contrarywind:Android-PickerView:4.1.3’ AddressP...
  • android省市区三联动实现

    千次阅读 2017-10-26 16:38:01
    使用的是github上的一个开源框架,又时间选择器、自定义条件选择器、我使用的是自定义地区选择器 ...2. 加载以及解析json数据 先声明三个存放数据的集合 private ArrayList options1Items = new ArrayList
  • 不过Android的列表选择框并不需要显示下拉列表,而是相当于弹出一个菜单供用户选择。 Spinner 与 Gallery 都继承了AbsSpinner,AbsSpinner 继承了AdapterView,因此它也表现出AdapterView的特征:只要为AdapterView...
  • Android中级列表ExpandableListView使用

    千次阅读 2015-08-07 15:14:15
    最近做级联操作,一菜单和二菜单的显示,发现Android官方自带了
  • 自定义PopupWindow实现3地区联动

    千次阅读 2014-06-10 09:30:13
    比如注册,买东西下单等,这里我在android上使用popupwindow实现3联动功能,我实现的思路是,当程序启动时就将后台的地区JSON数据格式全部加载上来,通过SharedPreferences将获取到的数据保存,点击按钮获取...
  • android安卓源码海量项目合集打包-1

    万次阅读 2019-06-11 16:16:24
    下载地址 最后更新共计113个分类5177套源码29.2 GB。...│ │ Android TagCloudView云标签的灵活运用.rar │ │ Android 实现 标签 拖动 改变位置.rar │ │ android 流式布局和热门标签.zip │ │ ...
  • NULL 博文链接:https://anduo.iteye.com/blog/2100137
  • Android的启动速度一直以来是他的诟病,虽然现在Android设备的硬件速度越来越快,但是随着新版本的出现,其启动速度一直都比较慢,当然,作为程序员,我们是可以理解的,智能手机本身就要启动很多服务来支持应用的...
  • 但是里面必须是有省市区的id,我才能回填省市区。如果遇到后端接口只给了省市区的name值。怎么办呢? 所以我优化了一下的province.js的文件。加个三个name。代表省市区的name值。 使用方法就是: ... ...
  • 但有时候需求的不变性,我们需要去做更多的处理,例如当我们需要获取开通省市区的地址id,省市区是由后台返回的数据,这个时候我们就需要对各级数据进行判空处理,并对数组进行越界保护。大致效果和加载本地没什么...
  • android -- Contacts 保存联系人

    千次阅读 2013-01-29 19:22:34
    主要是联系人的增删改查,很眼熟是不,应用大部分的任务都是围绕怎么获取数据获取、如何显示数据和保存修改数据进行的,联系人也不例外,而且把握数据的流向变化也算是分析应用的一个途径吧,同时数据的变化也在一点...
1 2 3 4 5 ... 20
收藏数 658
精华内容 263
关键字:

动态获取数据级联android