Android仿京东实现地址选择功能
最近在做地址管理的功能,新建地址的时候,需要根据后台提供的省市区的数据,让用户进行地址的选择,最近项目比较赶,本来想网上找一个的,可是找了很久都没找到我想要的效果,所以就根据后台提供的数据,弄了一个。
实现流程:
1、效果图
2、自定义收货地址选择器
3、设置点击按钮打开PopWindow进行地址选择
4、设置选择器默认数据
5、将获取的省市区的数据进行分类
6、设置地址选择器的布局文件
7、总结
实现步骤:
1、效果图

本来数据是根据请求后台接口返回的数据,我这里就不请求后台数据了,直接把请求成功后的数据写死,可是把全国省市区的数据太多,导致报错:字符串数据太长,所以我这里只获取了北京的数据。
2、自定义收货地址选择器
public class AddressSelector extends LinearLayout implements View.OnClickListener{private int TextSelectedColor = Color.parseColor("#D5A872");private int TextEmptyColor = Color.parseColor("#333333");//顶部的tab集合private ArrayList<Tab> tabs;//列表的适配器private AddressAdapter addressAdapter;private ArrayList<CityInterface> cities;private OnItemClickListener onItemClickListener;private OnTabSelectedListener onTabSelectedListener;private RecyclerView list;//tabs的外层layoutprivate LinearLayout tabs_layout;//会移动的横线布局private Line line;private Context mContext;//总共tab的数量private int tabAmount = 3;//当前tab的位置private int tabIndex = 0;//分隔线private View grayLine;//列表文字大小private int listTextSize = -1;//列表文字颜色private int listTextNormalColor = Color.parseColor("#333333");//列表文字选中的颜色private int listTextSelectedColor = Color.parseColor("#D5A872");//列表icon资源private int listItemIcon = -1;public AddressSelector(Context context) {super(context);init(context);}public AddressSelector(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public AddressSelector(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context){removeAllViews();this.mContext = context;setOrientation(VERTICAL);tabs_layout = new LinearLayout(mContext);tabs_layout.setWeightSum(tabAmount);tabs_layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));tabs_layout.setOrientation(HORIZONTAL);addView(tabs_layout);tabs = new ArrayList<>();Tab tab = newTab("请选择",true);tabs_layout.addView(tab);tabs.add(tab);for(int i = 1;i<tabAmount;i++){Tab _tab = newTab("",false);_tab.setIndex(i);tabs_layout.addView(_tab);tabs.add(_tab);}line = new Line(mContext);line.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,6));line.setSum(tabAmount);addView(line);grayLine = new View(mContext);grayLine.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,2));grayLine.setBackgroundColor(mContext.getResources().getColor(R.color.line_DDDDDD));addView(grayLine);list = new RecyclerView(mContext);list.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));list.setLayoutManager(new LinearLayoutManager(mContext));addView(list);}/*** 得到一个新的tab对象* */private Tab newTab(CharSequence text, boolean isSelected){Tab tab = new Tab(mContext);tab.setLayoutParams(new LayoutParams(0,LayoutParams.WRAP_CONTENT,1));tab.setGravity(Gravity.CENTER);tab.setPadding(0,5,0,5);tab.setSelected(isSelected);tab.setText(text);tab.setTextEmptyColor(TextEmptyColor);tab.setTextSelectedColor(TextSelectedColor);tab.setOnClickListener(this);return tab;}/*** 设置tab的数量,默认3个,不小于2个* @param tabAmount tab的数量* */public void setTabAmount(int tabAmount) {if(tabAmount >= 2){this.tabAmount = tabAmount;init(mContext);}elsethrow new RuntimeException("AddressSelector tabAmount can not less-than 2 !");}/*** 设置列表的点击事件回调接口* */public void setOnItemClickListener(OnItemClickListener onItemClickListener) {this.onItemClickListener = onItemClickListener;}/*** 设置列表的数据源,设置后立即生效* */public void setCities(ArrayList cities) {if(cities == null||cities.size() <= 0)return;if(cities.get(0) instanceof CityInterface){this.cities = cities;if(addressAdapter == null){addressAdapter = new AddressAdapter();list.setAdapter(addressAdapter);}addressAdapter.notifyDataSetChanged();}else{throw new RuntimeException("AddressSelector cities must implements CityInterface");}}/*** 设置顶部tab的点击事件回调* */public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {this.onTabSelectedListener = onTabSelectedListener;}public void onClick(View v) {Tab tab = (Tab) v;//如果点击的tab大于index则直接跳出if(tab.index > tabIndex)return;tabIndex = tab.index;if(onTabSelectedListener != null){if(tab.isSelected)onTabSelectedListener.onTabReselected(AddressSelector.this,tab);elseonTabSelectedListener.onTabSelected(AddressSelector.this,tab);}resetAllTabs(tabIndex);line.setIndex(tabIndex);tab.setSelected(true);}private void resetAllTabs(int tabIndex){if(tabs != null)for(int i =0;i<tabs.size();i++){tabs.get(i).resetState();if(i > tabIndex){tabs.get(i).setText("");}}}/*** 设置Tab文字选中的颜色* */public void setTextSelectedColor(int textSelectedColor) {TextSelectedColor = textSelectedColor;}/*** 设置Tab文字默认颜色* */public void setTextEmptyColor(int textEmptyColor) {TextEmptyColor = textEmptyColor;}/*** 设置Tab横线的颜色* */public void setLineColor(int lineColor) {line.setSelectedColor(lineColor);}/*** 设置tab下方分隔线的颜色* */public void setGrayLineColor(int grayLineColor) {grayLine.setBackgroundColor(grayLineColor);}/*** 设置列表文字大小* */public void setListTextSize(int listTextSize) {this.listTextSize = listTextSize;}/*** 设置列表文字颜色* */public void setListTextNormalColor(int listTextNormalColor) {this.listTextNormalColor = listTextNormalColor;}/*** 设置列表选中文字颜色* */public void setListTextSelectedColor(int listTextSelectedColor) {this.listTextSelectedColor = listTextSelectedColor;}/*** 设置列表icon资源* */public void setListItemIcon(int listItemIcon) {this.listItemIcon = listItemIcon;}/*** 标签控件* */("AppCompatCustomView")public class Tab extends TextView {private int index = 0;private int TextSelectedColor = Color.parseColor("#D5A872");private int TextEmptyColor = Color.parseColor("#333333");/*** 是否选中状态* */private boolean isSelected = false;public Tab(Context context) {super(context);init();}public Tab(Context context, AttributeSet attrs) {super(context, attrs);init();}public Tab(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init(){setTextSize(15);}public void setText(CharSequence text, BufferType type) {if(isSelected)setTextColor(TextSelectedColor);elsesetTextColor(TextEmptyColor);super.setText(text, type);}public void setSelected(boolean selected) {isSelected = selected;setText(getText());}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public void resetState(){isSelected = false;setText(getText());}public void setTextSelectedColor(int textSelectedColor) {TextSelectedColor = textSelectedColor;}public void setTextEmptyColor(int textEmptyColor) {TextEmptyColor = textEmptyColor;}}/*** 横线控件* */private class Line extends LinearLayout {private int sum = 3;private int oldIndex = 0;private int nowIndex = 0;private View indicator;private int SelectedColor = Color.parseColor("#D5A872");public Line(Context context) {super(context);init(context);}public Line(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public Line(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context){setOrientation(HORIZONTAL);setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,6));setWeightSum(tabAmount);indicator= new View(context);indicator.setLayoutParams(new LayoutParams(0,LayoutParams.MATCH_PARENT,1));indicator.setBackgroundColor(SelectedColor);addView(indicator);}public void setIndex(int index){int onceWidth = getWidth()/sum;this.nowIndex = index;ObjectAnimator animator = ObjectAnimator.ofFloat(indicator, "translationX", indicator.getTranslationX(), (nowIndex-oldIndex)*onceWidth);animator.setDuration(300);animator.start();}public void setSum(int sum) {this.sum = sum;}public void setSelectedColor(int selectedColor) {SelectedColor = selectedColor;}}private class AddressAdapter extends RecyclerView.Adapter<AddressAdapter.MyViewHolder>{public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {MyViewHolder viewHolder =new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_address,parent,false));return viewHolder;}public void onBindViewHolder(MyViewHolder holder, final int position) {if(listItemIcon != -1)holder.img.setImageResource(listItemIcon);if(listTextSize != -1)holder.tv.setTextSize(listTextSize);if(TextUtils.equals(tabs.get(tabIndex).getText(),cities.get(position).getCityName())){holder.img.setVisibility(View.VISIBLE);holder.tv.setTextColor(listTextSelectedColor);}else{holder.img.setVisibility(View.INVISIBLE);holder.tv.setTextColor(listTextNormalColor);}holder.tv.setText(cities.get(position).getCityName());holder.itemView.setTag(cities.get(position));holder.itemView.setOnClickListener(new OnClickListener() {public void onClick(View v) {if(onItemClickListener != null){onItemClickListener.itemClick(AddressSelector.this,(CityInterface) v.getTag(),tabIndex,position);tabs.get(tabIndex).setText(((CityInterface) v.getTag()).getCityName());tabs.get(tabIndex).setTag(v.getTag());if(tabIndex+1 < tabs.size()){tabIndex ++;resetAllTabs(tabIndex);line.setIndex(tabIndex);tabs.get(tabIndex).setText("请选择");tabs.get(tabIndex).setSelected(true);}}}});}public int getItemCount() {return cities.size();}class MyViewHolder extends RecyclerView.ViewHolder{public TextView tv;public ImageView img;public View itemView;public MyViewHolder(View itemView) {super(itemView);this.itemView = itemView;tv = (TextView) itemView.findViewById(R.id.item_address_tv);img = (ImageView) itemView.findViewById(R.id.item_address_img);}}}public interface OnTabSelectedListener {void onTabSelected(AddressSelector addressSelector, Tab tab);void onTabReselected(AddressSelector addressSelector, Tab tab);}}
3、Demo中设置点击按钮打开PopWindow进行地址选择
/*** 设置弹出PopWindow* @param v*/private void setAddressSelectorPopup(View v) {int screenHeigh = getResources().getDisplayMetrics().heightPixels;CommonPopWindow.newBuilder().setView(R.layout.pop_address_selector_bottom).setAnimationStyle(R.style.AnimUp).setBackgroundDrawable(new BitmapDrawable()).setSize(ViewGroup.LayoutParams.MATCH_PARENT, Math.round(screenHeigh * 0.6f)).setViewOnClickListener(this).setBackgroundDarkEnable(true).setBackgroundAlpha(0.7f).setBackgroundDrawable(new ColorDrawable(999999)).build(this).showAsBottom(v);}public void getChildView(final PopupWindow mPopupWindow, View view, int mLayoutResId) {switch (mLayoutResId) {case R.layout.pop_address_selector_bottom:ImageView imageBtn = view.findViewById(R.id.img_guanbi);AddressSelector addressSelector = view.findViewById(R.id.address);//数据解析AddressSelectorReq addressSelectorReq = new Gson().fromJson(String.valueOf(response), AddressSelectorReq.class);//设置默认选择数据dealWithAddressSelector(addressSelector, addressSelectorReq.getDatas(), mPopupWindow);imageBtn.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {mPopupWindow.dismiss();}});break;}}
4、设置选择器默认数据
private void dealWithAddressSelector(AddressSelector addressSelector, final List<AddressSelectorReq.DatasBean>addressSelectorList, final PopupWindow mPopupWindow) {final String[] sheng = new String[3];final ArrayList<ItemAddressReq> itemAddressReqs = getItemAddressSheng(addressSelectorList);addressSelector.setTabAmount(3);//设置数据addressSelector.setCities(itemAddressReqs);//设置Tab横线的颜色addressSelector.setLineColor(Color.parseColor("#D5A872"));//设置Tab文字默认颜色addressSelector.setTextEmptyColor(Color.parseColor("#000000"));//设置列表选中文字颜色addressSelector.setListTextSelectedColor(Color.parseColor("#D5A872"));//设置Tab文字选中的颜色addressSelector.setTextSelectedColor(Color.parseColor("#D5A872"));//设置列表的点击事件回调接口addressSelector.setOnItemClickListener(new OnItemClickListener() {public void itemClick(AddressSelector addressSelector, CityInterface city, int tabPosition, int selecePos) {switch (tabPosition) {case 0://设置省列表数据sheng[0] = city.getCityName();saveId[0] = addressSelectorList.get(selecePos).getDb_id();childrenBeanXList = addressSelectorList.get(selecePos).getDb_children();addressSelector.setCities(getItemAddressShi(childrenBeanXList));break;case 1://设置市列表数据sheng[1] = city.getCityName();saveId[1] = childrenBeanXList.get(selecePos).getCb_id();childrenBeans = childrenBeanXList.get(selecePos).getCb_children();addressSelector.setCities(getItemAddressQu(childrenBeans));break;case 2://设置区列表数据sheng[2] = city.getCityName();saveId[2] = childrenBeans.get(selecePos).getId();text_suozaidiqu.setText(sheng[0] + sheng[1] + sheng[2]);mPopupWindow.dismiss();break;}}});//设置顶部tab的点击事件回调addressSelector.setOnTabSelectedListener(new AddressSelector.OnTabSelectedListener() {public void onTabSelected(AddressSelector addressSelector, AddressSelector.Tab tab) {switch (tab.getIndex()) {case 0:addressSelector.setCities(itemAddressReqs);break;case 1:addressSelector.setCities(getItemAddressShi(childrenBeanXList));break;case 2:addressSelector.setCities(getItemAddressQu(childrenBeans));break;}}public void onTabReselected(AddressSelector addressSelector, AddressSelector.Tab tab) {}});}
5、将获取的省市区的数据进行分类
/*** 获取省的数据** @param addressSelectorList* @return*/@NonNullprivate ArrayList<ItemAddressReq> getItemAddressSheng(List<AddressSelectorReq.DatasBean> addressSelectorList) {final ArrayList<ItemAddressReq> itemAddressReqs = new ArrayList<>();for (int i = 0; i < addressSelectorList.size(); i++) {ItemAddressReq itemAddressReq = new ItemAddressReq();itemAddressReq.setAreaAbbName(addressSelectorList.get(i).getDb_areaAbbName());itemAddressReq.setAreaCode(addressSelectorList.get(i).getDb_areaCode());itemAddressReq.setAreaEnName(addressSelectorList.get(i).getDb_areaEnName());itemAddressReq.setAreaType(addressSelectorList.get(i).getDb_areaType());itemAddressReq.setAreaZip(addressSelectorList.get(i).getDb_areaZip());itemAddressReq.setAreaName(addressSelectorList.get(i).getDb_areaName());itemAddressReq.setId(addressSelectorList.get(i).getDb_id());itemAddressReq.setParentId(addressSelectorList.get(i).getDb_parentId());itemAddressReqs.add(itemAddressReq);}return itemAddressReqs;}/*** 获取市的数据** @return*/@NonNullprivate ArrayList<ItemAddressReq> getItemAddressShi(List<AddressSelectorReq.DatasBean.ChildrenBeanX> datas) {final ArrayList<ItemAddressReq> itemAddressReqs = new ArrayList<>();for (int i = 0; i < datas.size(); i++) {ItemAddressReq itemAddressReq = new ItemAddressReq();itemAddressReq.setAreaAbbName(datas.get(i).getCb_areaAbbName());itemAddressReq.setAreaCode(datas.get(i).getCb_areaCode());itemAddressReq.setAreaEnName(datas.get(i).getCb_areaEnName());itemAddressReq.setAreaType(datas.get(i).getCb_areaType());itemAddressReq.setAreaZip(datas.get(i).getCb_areaZip());itemAddressReq.setAreaName(datas.get(i).getCb_areaName());itemAddressReq.setId(datas.get(i).getCb_id());itemAddressReq.setParentId(datas.get(i).getCb_parentId());itemAddressReqs.add(itemAddressReq);}return itemAddressReqs;}/*** 获取区的数据** @param addressSelectorList* @return*/@NonNullprivate ArrayList<ItemAddressReq> getItemAddressQu(List<AddressSelectorReq.DatasBean.ChildrenBeanX.ChildrenBean> addressSelectorList) {final ArrayList<ItemAddressReq> itemAddressReqs = new ArrayList<>();for (int i = 0; i < addressSelectorList.size(); i++) {ItemAddressReq itemAddressReq = new ItemAddressReq();itemAddressReq.setAreaAbbName(addressSelectorList.get(i).getAreaAbbName());itemAddressReq.setAreaCode(addressSelectorList.get(i).getAreaCode());itemAddressReq.setAreaEnName(addressSelectorList.get(i).getAreaEnName());itemAddressReq.setAreaType(addressSelectorList.get(i).getAreaType());itemAddressReq.setAreaZip(addressSelectorList.get(i).getAreaZip());itemAddressReq.setAreaName(addressSelectorList.get(i).getAreaName());itemAddressReq.setId(addressSelectorList.get(i).getId());itemAddressReq.setParentId(addressSelectorList.get(i).getParentId());itemAddressReqs.add(itemAddressReq);}return itemAddressReqs;}
6、设置地址选择器的布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:background="#fff"android:orientation="vertical"android:padding="1dp"><ImageViewandroid:id="@+id/img_guanbi"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginTop="15dp"android:layout_marginRight="15dp"android:src="@drawable/guanbi" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_marginTop="30dp"android:text="所在区域"android:textColor="#777777"android:textSize="16sp" /><com.showly.ylin.addressselectdemo.addressselector.AddressSelectorandroid:id="@+id/address"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="70dp" /></RelativeLayout>
7、总结
到这里就实现了地址选择器的功能,因为后台提供的地址数据可能不一样,所以这里就不把全部数据拿出来了,需要完整数据的也可以Q我。
需要Demo的童鞋可以在公众号回复 “地址选择器”
到这里就结束啦
评论
