使用Android如何实现四级联动地址选择器?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
效果如下:
代码传送阵:
address_selector.xml
<LinearLayout 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:id="@+id/ll_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:alpha="0"
android:background="#b2000000"
android:orientation="vertical"
tools:alpha="1">
<android.support.constraint.ConstraintLayout
android:id="@+id/cl_container"
android:clickable="true"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/selector_bg">
<TextView
android:id="@+id/textViewProvince"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_42"
android:layout_marginStart="@dimen/dp_18"
android:ellipsize="end"
android:paddingTop="@dimen/dp_13"
android:maxWidth="@dimen/dp_80"
android:maxLines="1"
android:text="请选择"
android:textColor="@drawable/selector_item_text_color"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="请选择请选择"
tools:visibility="visible" />
<TextView
android:id="@+id/textViewCity"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_44"
android:layout_marginStart="@dimen/dp_21"
android:ellipsize="end"
android:paddingTop="@dimen/dp_13"
android:maxWidth="@dimen/dp_80"
android:maxLines="1"
android:text="请选择"
android:textColor="@drawable/selector_item_text_color"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
android:visibility="invisible"
app:layout_constraintLeft_toRightOf="@id/textViewProvince"
app:layout_constraintTop_toTopOf="parent"
tools:text="请选择请选择"
tools:visibility="visible" />
<TextView
android:id="@+id/textViewArea"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_44"
android:layout_marginStart="@dimen/dp_21"
android:ellipsize="end"
android:paddingTop="@dimen/dp_13"
android:maxWidth="@dimen/dp_80"
android:maxLines="1"
android:text="请选择"
android:textColor="@drawable/selector_item_text_color"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
android:visibility="invisible"
app:layout_constraintLeft_toRightOf="@id/textViewCity"
app:layout_constraintTop_toTopOf="parent"
tools:text="请选择请选择"
tools:visibility="visible" />
<TextView
android:id="@+id/textViewStreet"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_44"
android:layout_marginStart="@dimen/dp_21"
android:ellipsize="end"
android:paddingTop="@dimen/dp_13"
android:maxWidth="@dimen/dp_80"
android:maxLines="1"
android:text="请选择"
android:textColor="@drawable/selector_item_text_color"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
android:visibility="invisible"
app:layout_constraintLeft_toRightOf="@id/textViewArea"
app:layout_constraintTop_toTopOf="parent"
tools:text="请选择请选择"
tools:visibility="visible" />
<android.support.v7.widget.AppCompatImageView
android:id="@+id/iv_close"
android:layout_width="@dimen/dp_23"
android:layout_height="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_12"
android:layout_marginEnd="@dimen/dp_12"
android:padding="@dimen/dp_5"
android:src="@drawable/address_close"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/indicator"
android:layout_width="@dimen/dp_24"
android:layout_height="@dimen/dp_2"
android:background="#000000"
app:layout_constraintLeft_toLeftOf="@id/textViewProvince"
app:layout_constraintTop_toBottomOf="@id/textViewProvince" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#e5e5e5"
app:layout_constraintTop_toBottomOf="@id/indicator" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider" />
</android.support.constraint.ConstraintLayout>
</LinearLayout>
AddressDialog.java
public class AddressDialog extends DialogFragment {
@BindView(R.id.textViewProvince)
TextView textViewProvince;
@BindView(R.id.textViewCity)
TextView textViewCity;
@BindView(R.id.textViewArea)
TextView textViewArea;
@BindView(R.id.textViewStreet)
TextView textViewStreet;
@BindView(R.id.iv_close)
AppCompatImageView ivClose;
@BindView(R.id.indicator)
View indicator;
@BindView(R.id.divider)
View divider;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@BindView(R.id.cl_container)
ConstraintLayout clContainer;
@BindView(R.id.ll_container)
LinearLayout llContainer;
Unbinder unbinder;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private float measuredHeight = 0F;
// 当前tab 0省1市2区
private int currentTab = 0;
// 省
private ArrayList<County> proviceList = new ArrayList<>();
// 市
private ArrayList<County> cityList = new ArrayList<>();
private ConcurrentHashMap<String, ArrayList<County>> cityMap = new ConcurrentHashMap<>();
// 区
private ArrayList<County> areaList = new ArrayList<>();
private ConcurrentHashMap<String, ArrayList<County>> areaMap = new ConcurrentHashMap<>();
//街道
private ArrayList<County> streetList = new ArrayList<>();
private ConcurrentHashMap<String, ArrayList<County>> streetMap = new ConcurrentHashMap<>();
private BaseQuickAdapter<County, BaseViewHolder> mAdapter;
private OnSelectListener listener;
private String textProvince = "";
private String textCity = "";
private String textArea = "";
private String textStreet = "";
private ProgressDialog mProgressDialog;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.address_selector, container, false);
unbinder = ButterKnife.bind(this, view);
return view;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_TITLE, R.style.Style_Dialog_Transparent);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textViewProvince.setSelected(true);
float measureText = textViewProvince.getPaint().measureText("请选择");
indicator.getLayoutParams().width = (int) measureText;
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)clContainer.getLayoutParams();
layoutParams.topMargin = listener.getHeight() == 0 ? UIUtil.dip2px(MyApplication.applicationContext,180f) :listener.getHeight();
clContainer.setLayoutParams(layoutParams);
initData();
initClick();
ViewUtils.postMeasured(clContainer, new Runnable() {
@Override
public void run() {
llContainer.animate().alpha(1f).setDuration(150).start();
float measuredHeight = (float)clContainer.getMeasuredHeight();
ObjectAnimator translationY = ObjectAnimator.ofFloat(clContainer, "translationY", measuredHeight, 0f);
translationY.setDuration(150);
translationY.setInterpolator(new LinearInterpolator());
translationY.start();
}
});
}
private void initData() {
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mAdapter=new BaseQuickAdapter<County, BaseViewHolder>(R.layout.item_area) {
@Override
protected void convert(@NonNull BaseViewHolder helper, final County item) {
helper.setText(R.id.textView,item.name);
helper.getConvertView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (currentTab) {
case 0:
getCityList(new Consumer<ArrayList<County>>() {
@Override
public void accept(ArrayList<County> counties) throws Exception {
// 本地是否存在
if (cityMap.containsKey(item.code)){
ArrayList<County> list = cityMap.get(item.code);
if (list==null) {
list=new ArrayList<>();
}
notifyAdapter(list);
}else {
for (County next : cityList) {
if (cityMap.containsKey(item.code) && item.code.equals(next.provinceCode)) {
ArrayList<County> list = cityMap.get(item.code);
if (list != null) {
list.add(next);
cityMap.put(next.provinceCode, list);
}
} else {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
ArrayList<County> listCounty = new ArrayList<>();
listCounty.add(next);
cityMap.put(next.provinceCode, listCounty);
}
}
}
ArrayList<County> list = cityMap.get(item.code);
notifyAdapter(list);
}
});
break;
case 1:
getAreaList(new Consumer<ArrayList<County>>() {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Override
public void accept(ArrayList<County> list) throws Exception {
if (areaMap.containsKey(item.code)) {
ArrayList<County> arrayList = areaMap.get(item.code);
if (arrayList==null) {
arrayList =new ArrayList<>();
}
notifyAdapter(arrayList);
}else {
for (County county : areaList) {
if (areaMap.containsKey(item.code) && item.code.equals(county.cityCode)) {
ArrayList<County> countyArrayList = areaMap.get(item.code);
if (countyArrayList != null) {
countyArrayList.add(county);
areaMap.put(county.code, countyArrayList);
}
}else {
ArrayList<County> arrayList = new ArrayList<>();
arrayList.add(county);
areaMap.put(county.cityCode,arrayList);
}
}
}
ArrayList<County> arrayList = areaMap.get(item.code);
notifyAdapter(arrayList);
}
});
break;
case 2:
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(getActivity());
}
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setCancelable(true);
mProgressDialog.show();
getStreetList(new Consumer<ArrayList<County>>() {
@Override
public void accept(ArrayList<County> list) throws Exception {
if (streetMap.containsKey(item.code)) {
ArrayList<County> arrayList = streetMap.get(item.code);
if (arrayList==null) {
arrayList =new ArrayList<>();
}
notifyAdapter(arrayList);
}else {
for (County county : streetList) {
if (streetMap.containsKey(item.code) && item.code.equals(county.areaCode)) {
ArrayList<County> countyArrayList = streetMap.get(item.code);
if (countyArrayList != null) {
countyArrayList.add(county);
streetMap.put(county.code, countyArrayList);
}
}else {
ArrayList<County> arrayList = new ArrayList<>();
arrayList.add(county);
streetMap.put(county.areaCode,arrayList);
}
}
}
ArrayList<County> arrayList = streetMap.get(item.code);
notifyAdapter(arrayList);
if (mProgressDialog != null) {
ThreadHelper.getInstance().runOnUiPostDelayed(new Runnable() {
@Override
public void run() {
mProgressDialog.dismiss();
}
},1000);
}
}
});
}
upTabStatus(item.name);
indicatorAnim();
}
});
}
};
recyclerView.setAdapter(mAdapter);
getProvinceList(new Consumer<ArrayList<County>>() {
@Override
public void accept(ArrayList<County> list) throws Exception {
notifyAdapter(proviceList);
}
});
}
private void initClick() {
ivClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeDialog();
}
});
llContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeDialog();
}
});
}
private void notifyAdapter(ArrayList<County> list){
mAdapter.getData().clear();
mAdapter.addData(list);
}
//indicator 动画
private void indicatorAnim(){
switch (currentTab){
case 1:
float text = textViewProvince.getPaint().measureText(textProvince);
indicator.animate().translationX(text+UIUtil.dip2pxf(Objects.requireNonNull(getContext()),21f)).setDuration(200).start();
break;
case 2:
float measureText = textViewProvince.getPaint().measureText(textProvince);
float measureText1 = textViewCity.getPaint().measureText(textCity);
indicator.animate().translationX(measureText+measureText1+UIUtil.dip2pxf(Objects.requireNonNull(getContext()),42f)).setDuration(200).start();
break;
case 3:
float measure = textViewProvince.getPaint().measureText(textProvince);
float measure1 = textViewCity.getPaint().measureText(textCity);
float measure2 = textViewArea.getPaint().measureText(textArea);
indicator.animate().translationX(measure+measure1+measure2+UIUtil.dip2pxf(Objects.requireNonNull(getContext()),63f)).setDuration(200).start();
}
}
private void upTabStatus(String name){
switch (currentTab){
case 0:
textProvince=name;
textViewProvince.setText(name);
textViewCity.setVisibility(View.VISIBLE);
currentTab =1;
break;
case 1:
textCity=name;
textViewCity.setText(name);
textViewArea.setVisibility(View.VISIBLE);
currentTab =2;
break;
case 2:
textArea=name;
textViewArea.setText(name);
textViewStreet.setVisibility(View.VISIBLE);
currentTab=3;
break;
case 3:
textStreet=name;
textViewStreet.setText(name);
dismissAllowingStateLoss();
break;
}
textViewProvince.setSelected(currentTab==0);
textViewCity.setSelected(currentTab==1);
textViewArea.setSelected(currentTab==2);
textViewStreet.setSelected(currentTab==3);
}
private void getProvinceList(Consumer<ArrayList<County>> consumer){
Disposable subscribe1 = Observable.create((new ObservableOnSubscribe() {
public final void subscribe(@NonNull ObservableEmitter it) {
if (proviceList.isEmpty()) {
String json = getJson("address/provinces.json", getContext());
ArrayList<County> list = fromJson(json,new TypeToken<ArrayList<County>>(){}.getType());
if (list==null) {
list =new ArrayList<>();
}
proviceList.addAll(list);
}
if (!proviceList.isEmpty()) {
it.onNext(proviceList);
}
}
})).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(consumer, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
});
compositeDisposable.add(subscribe1);
}
private void getCityList(Consumer<ArrayList<County>> consumer){
Disposable subscribe1 = Observable.create((new ObservableOnSubscribe() {
public final void subscribe(@NonNull ObservableEmitter it) {
if (cityList.isEmpty()) {
String json = getJson("address/cities.json", getContext());
ArrayList<County> list = fromJson(json,new TypeToken<ArrayList<County>>(){}.getType());
if (list==null) {
list =new ArrayList<>();
}
cityList.addAll(list);
}
if (!cityList.isEmpty()) {
it.onNext(cityList);
}
}
})).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(consumer, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
});
compositeDisposable.add(subscribe1);
}
private void getAreaList(Consumer<ArrayList<County>> consumer){
Disposable subscribe1 = Observable.create((new ObservableOnSubscribe() {
public final void subscribe(@NonNull ObservableEmitter it) {
if (areaList.isEmpty()) {
String json = getJson("address/areas.json", getContext());
ArrayList<County> list = fromJson(json,new TypeToken<ArrayList<County>>(){}.getType());
if (list==null) {
list =new ArrayList<>();
}
areaList.addAll(list);
}
if (!areaList.isEmpty()) {
it.onNext(areaList);
}
}
})).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(consumer, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
});
compositeDisposable.add(subscribe1);
}
private void getStreetList(Consumer<ArrayList<County>> consumer){
Disposable subscribe1 = Observable.create((new ObservableOnSubscribe() {
public final void subscribe(@NonNull ObservableEmitter it) {
if (streetList.isEmpty()) {
String json = getJson("address/streets.json", getContext());
ArrayList<County> list = fromJson(json,new TypeToken<ArrayList<County>>(){}.getType());
if (list==null) {
list =new ArrayList<>();
}
streetList.addAll(list);
}
if (!streetList.isEmpty()) {
it.onNext(streetList);
}
}
})).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(consumer, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
});
compositeDisposable.add(subscribe1);
}
public String getJson(String fileName, Context context) {
StringBuilder stringBuilder = new StringBuilder();
try {
InputStream is = context.getAssets().open(fileName);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
@Nullable
public <T> T fromJson(String json, Type typeOfT) {
try {
return initGson().fromJson(json, typeOfT);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
return null;
}
private Gson initGson(){
GsonBuilder gsonBuilder = new GsonBuilder();
try {
Class builder = gsonBuilder.getClass();
Field f = builder.getDeclaredField("instanceCreators");
f.setAccessible(true);
Map<Type, InstanceCreator<?>> val = (Map<Type, InstanceCreator<?>>) f.get(gsonBuilder);//得到此属性的值
//注册数组的处理器
ConstructorConstructor constructorConstructor = new ConstructorConstructor(val);
// gsonBuilder.registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(constructorConstructor, FieldNamingPolicy.IDENTITY,
// Excluder.DEFAULT,new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor)));
gsonBuilder.registerTypeAdapterFactory(new MapTypeAdapterFactory(constructorConstructor,false));
gsonBuilder.registerTypeAdapterFactory(new CollectionTypeAdapterFactory(constructorConstructor));
// gsonBuilder.registerTypeAdapter(String.class,new StringTypeAdapter());
gsonBuilder.registerTypeAdapter(int.class,new IntegerTypeAdapter());
gsonBuilder.registerTypeAdapter(Integer.class,new IntegerTypeAdapter());
// gsonBuilder.registerTypeAdapter(long.class,new LongTypeAdapter());
// gsonBuilder.registerTypeAdapter(Long.class,new LongTypeAdapter());
// gsonBuilder.registerTypeAdapter(double.class,new DoubleTypeAdapter());
// gsonBuilder.registerTypeAdapter(Double.class,new DoubleTypeAdapter());
// gsonBuilder.registerTypeAdapter(boolean.class,new BooleanTypeAdapter());
// gsonBuilder.registerTypeAdapter(Boolean.class,new BooleanTypeAdapter());
// gsonBuilder.registerTypeAdapter(float.class,new FloadTypeAdapter());
// gsonBuilder.registerTypeAdapter(Float.class,new FloadTypeAdapter());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return gsonBuilder.enableComplexMapKeySerialization().create();
}
public void closeDialog() {
clContainer.animate().translationY(measuredHeight).setDuration(150).withEndAction(new Runnable() {
@Override
public void run() {
dismissAllowingStateLoss();
}
}).start();
}
public void dismissAllowingStateLoss() {
super.dismissAllowingStateLoss();
if (!TextUtils.isEmpty(textProvince) && !TextUtils.isEmpty(textCity) && !TextUtils.isEmpty(textArea)&&!TextUtils.isEmpty(textStreet)) {
listener.onSelect(textProvince, textCity, textCity,textStreet);
}
listener.isMissing();
compositeDisposable.dispose();
}
public void setOnSelectListener(OnSelectListener listener) {
this.listener = listener;
}
public void setHeight(int top) {
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
public interface OnSelectListener {
int getHeight();
void onSelect(String province, String city, String area,String street);
void isMissing();
}
}
使用方法
private void addressDialog() {
AddressDialog addressDialog =new AddressDialog();
addressDialog.setOnSelectListener(new AddressDialog.OnSelectListener() {
@Override
public int getHeight() {
return 0;
}
@SuppressLint("SetTextI18n")
@Override
public void onSelect(String province, String city, String area, String street) {
tvPositionRtrCommunity.setText(province+" "+city+" "+area+" "+street);
}
@Override
public void isMissing() {
isShowDialog = true;
}
});
addressDialog.show(getSupportFragmentManager(),AddressDialog.class.getSimpleName());
}
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注天达云行业资讯频道,感谢您对天达云的支持。