最近在做一個社交類APP時,希望用戶在注冊時根據地區來選擇自己所在的學校,由於用戶手動輸入學校,可能會出現各種問題,不利於后面對用戶信息的統計。於是決定在客戶端做好設置,用戶只要根據地區來選擇就好。第一想法就是使用PopupWindow,用彈框的方式讓用戶來選擇。讓實現的效果如下:


下面就來講一下是如何實現的(數據是從網絡獲取的,JSON解析使用的是Gson,網絡庫用的是Volley)
工程結構:

1、創建一個布局文件:view_select_province_list.xml,主要包括一個TextView(用來顯示標題)和兩個ListView(默認顯示地區ListView,隱藏SchoolListView)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/list_title" android:layout_width="match_parent" android:layout_height="50dp" android:background="#3b3b3b" android:gravity="center" android:text="選擇地區" android:textColor="#ffffff" android:textSize="16sp"/> <ListView android:id="@+id/province" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:background="#e4e4e4" android:divider="#aeaeae" android:dividerHeight="1dp"></ListView> <ListView android:id="@+id/school" android:visibility="gone" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:background="#e4e4e4" android:divider="#aeaeae" android:dividerHeight="1dp"></ListView> </LinearLayout>
2、初始化PopupWindow
private void initPopView() { parent = this.getWindow().getDecorView(); View popView = View.inflate(this, R.layout.view_select_province_list, null); mTitle = (TextView) popView.findViewById(R.id.list_title); mProvinceListView = (ListView) popView.findViewById(R.id.province); mSchoolListView = (ListView) popView.findViewById(R.id.school); mProvinceListView.setOnItemClickListener(itemListener); mSchoolListView.setOnItemClickListener(itemListener); mProvinceAdapter = new ProvinceAdapter(this); mProvinceListView.setAdapter(mProvinceAdapter); mSchoolAdapter = new SchoolAdapter(this); mSchoolListView.setAdapter(mSchoolAdapter); int width = getResources().getDisplayMetrics().widthPixels * 3 / 4; int height = getResources().getDisplayMetrics().heightPixels * 3 / 5; mPopWindow = new PopupWindow(popView, width, height); ColorDrawable dw = new ColorDrawable(0x30000000); mPopWindow.setBackgroundDrawable(dw); mPopWindow.setFocusable(true); mPopWindow.setTouchable(true); mPopWindow.setOutsideTouchable(true);//允許在外側點擊取消 loadProvince(); mPopWindow.setOnDismissListener(listener); }
其中,要想使PopupWindow點擊空白區域取消,必須設置
ColorDrawable dw = new ColorDrawable(0x30000000);
mPopWindow.setBackgroundDrawable(dw);
mPopWindow.setOutsideTouchable(true);
3、顯示PopupWindow
private void showPopWindow()
{ mPopWindow.showAtLocation(parent, Gravity.CENTER, 0, 0);}
4、下載地區和學校數據(這里用的是volley和gson解析數據)
private void loadProvince() { mRequestQueue = Volley.newRequestQueue(this); GsonRequest<Province> request = new GsonRequest<Province>(Request.Method.POST, Config.PROVINCE_URL, Province.class, new Response.Listener<Province>() { @Override public void onResponse(Province response) { if (response.getData() != null && response.getError_code() == 0) { mProvinceAdapter.setList(response.getData()); mProvinceAdapter.notifyDataSetChanged(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } }, this); mRequestQueue.add(request); } private void loadSchool() { mRequestQueue = Volley.newRequestQueue(this); GsonRequest<School> request = new GsonRequest<>(Request.Method.POST, Config.SCHOOL_URL + provinceId, School.class, new Response.Listener<School>() { @Override public void onResponse(School response) { if (response.getData() != null && response.getError_code() == 0){ mSchoolAdapter.setList(response.getData()); mSchoolAdapter.notifyDataSetChanged(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } }, this); mRequestQueue.add(request); }
5、設置ListView 的Item點擊事件
/** * ListView Item點擊事件 */ AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (parent == mProvinceListView) { ProvinceList provinceName = (ProvinceList) mProvinceListView.getItemAtPosition(position); provinceId = provinceName.getProvince_id(); mTitle.setText("選擇學校"); mProvinceListView.setVisibility(View.GONE);//隱藏地區 mSchoolListView.setVisibility(View.VISIBLE);//顯示學校 loadSchool(); } else if (parent == mSchoolListView) { SchoolList schoolName = (SchoolList) mSchoolListView.getItemAtPosition(position); mSelectSchool.setText(schoolName.getSchool_name()); mPopWindow.dismiss(); } } };
6、PopupWindow設置OnDismissListener,目的是為了再次進入選擇的時候,直接進入學校而不是地區的選擇
/** * popWindow消失監聽事件 */ PopupWindow.OnDismissListener listener = new PopupWindow.OnDismissListener() { @Override public void onDismiss() { mTitle.setText("選擇地區"); mProvinceListView.setVisibility(View.VISIBLE);//顯示地區 mSchoolAdapter.setList(new ArrayList<SchoolList>());//設置一個空的List,避免再次選擇學校后彈出的還是剛才的地區對應的學校 mSchoolAdapter.notifyDataSetChanged(); mSchoolListView.setVisibility(View.GONE);//隱藏學校 } };
7、好了,這樣一個基於PopupWindow的二級聯動彈框選擇就完成了,其中,還有ListView的Adapter在這里我就沒有貼出來了,寫法和我們平常用的適配器一樣。我已經把代碼開源到我的GitHub上了,有需要的可以下載看看。
GitHub地址:https://github.com/tonycheng93/PopWindow
