是採用的github開源庫PickerView,省時省力。最終效果圖見最後
首先添加依賴:
//PickerView 選擇器 implementation 'com.contrarywind:Android-PickerView:4.1.9' //谷歌Gson implementation 'com.google.code.gson:gson:2.8.6' //eventbus implementation 'org.greenrobot:eventbus:3.2.0'
Gson是在解析地址文件的時候要用,eventbus是傳遞選擇的數據的時候要用。
因爲他給的佈局通常是不太符合你實際需求的,所以使用自定義佈局的方式,先去寫好自己的佈局文件,如地址的
picker_location.xml
因爲有多個地方要重用選擇器的部分,所以我使用include方便重用:
include_picker_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="280dp"
android:background="@drawable/shape_picker_bg">
<TextView
android:id="@+id/include_picker_tv_cancle"
android:layout_width="30dp"
android:layout_height="30dp"
android:text="取消"
android:textSize="14dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:textColor="@color/black_1A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/include_picker_tv_submit"
android:layout_width="30dp"
android:layout_height="30dp"
android:text="確定"
android:textSize="14dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:textColor="@color/gray_9A"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/optionspicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="150dp"
android:gravity="center"
android:background="@android:color/white"
android:orientation="horizontal"
android:layout_marginTop="20dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<com.contrarywind.view.WheelView
android:id="@+id/options1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/options2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/options3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
我將這幾個封裝成了一個工具類,其中顯示地址的代碼:
private OptionsPickerView locationOptions;
//顯示地址選擇器
public void showLocationPicker() {// 彈出選擇器
if(!isLoaded){
Toast.makeText(context,context.getResources().getString(R.string.loading_location_data),Toast.LENGTH_SHORT).show();
return;
}
locationOptions = new OptionsPickerBuilder(context, new OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int options2, int options3, View v) {
//
}
})
.setLayoutRes(R.layout.picker_location, new CustomListener() {
@Override
public void customLayout(View v) {
final TextView tvSubmit = v.findViewById(R.id.picker_location_inc_bg).findViewById(R.id.include_picker_tv_submit);
final TextView tvCancle = v.findViewById(R.id.picker_location_inc_bg).findViewById(R.id.include_picker_tv_cancle);
tvSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!isChanged){//沒有改變默認選擇第一項
String firstLocation = options1Items.get(0).getPickerViewText() + "\t" + options2Items.get(0).get(0);
EventBus.getDefault().post(new PickerMessageEvent(MESSAGE_TYPE_LOCATION,firstLocation,"0"));
}else {
EventBus.getDefault().post(new PickerMessageEvent(MESSAGE_TYPE_LOCATION,checkedLocation,"0"));
}
locationOptions.dismiss();
}
});
}
})
.setOptionsSelectChangeListener(new OnOptionsSelectChangeListener() {
@Override
public void onOptionsSelectChanged(int options1, int options2, int options3) {
String opt1tx = options1Items.size() > 0 ?
options1Items.get(options1).getPickerViewText() : "";
String opt2tx = options2Items.size() > 0
&& options2Items.get(options1).size() > 0 ?
options2Items.get(options1).get(options2) : "";
checkedLocation = opt1tx + "\t" + opt2tx;
isChanged = true;
}
})
.setLineSpacingMultiplier(2.4f)//設置距離
.setItemVisibleCount(3)//設置顯示的數據數量
.setContentTextSize(17)//設置標題字號
.isRestoreItem(true)//是否每次從頭開始顯示數據
.isAlphaGradient(true)
.build();
locationOptions.setPicker(options1Items, options2Items);
locationOptions.show();
}
//初始化地區數據
private void initJsonData() {//解析數據
/**
* 注意:assets 目錄下的Json文件僅供參考,實際使用可自行替換文件
* 關鍵邏輯在於循環體
*
* */
String JsonData = new GetJsonDataUtil().getJson(context, "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());
}*/
// city_AreaList.addAll(jsonBean.get(i).getCityList().get(c).getArea());
// province_AreaList.add(city_AreaList);//添加該省所有地區數據
}
/**
* 添加城市數據
*/
options2Items.add(cityList);
/**
* 添加地區數據
*/
// options3Items.add(province_AreaList);
}
mHandler.sendEmptyMessage(MSG_LOAD_SUCCESS);
}
//解析地區json文件
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();
mHandler.sendEmptyMessage(MSG_LOAD_FAILED);
}
return detail;
}
public void removeHandler(){
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
}
其中
String JsonData = new GetJsonDataUtil().getJson(context, "province.json");//獲取assets目錄下的json文件數據
是一份地址數據文件放在本地assets。
JsonBean和GetJsonDataUtil請參照源碼,不過多解釋。
最後效果:
自己需要什麼樣的效果就通過佈局文件和locationOptions.set...去設置
源碼: