Android仿京東實(shí)現(xiàn)地址選擇功能
最近在做地址管理的功能,新建地址的時(shí)候,需要根據(jù)后臺(tái)提供的省市區(qū)的數(shù)據(jù),讓用戶進(jìn)行地址的選擇,最近項(xiàng)目比較趕,本來想網(wǎng)上找一個(gè)的,可是找了很久都沒找到我想要的效果,所以就根據(jù)后臺(tái)提供的數(shù)據(jù),弄了一個(gè)。
實(shí)現(xiàn)流程:
1、效果圖
2、自定義收貨地址選擇器
3、設(shè)置點(diǎn)擊按鈕打開PopWindow進(jìn)行地址選擇
4、設(shè)置選擇器默認(rèn)數(shù)據(jù)
5、將獲取的省市區(qū)的數(shù)據(jù)進(jìn)行分類
6、設(shè)置地址選擇器的布局文件
7、總結(jié)
實(shí)現(xiàn)步驟:
1、效果圖

本來數(shù)據(jù)是根據(jù)請求后臺(tái)接口返回的數(shù)據(jù),我這里就不請求后臺(tái)數(shù)據(jù)了,直接把請求成功后的數(shù)據(jù)寫死,可是把全國省市區(qū)的數(shù)據(jù)太多,導(dǎo)致報(bào)錯(cuò):字符串?dāng)?shù)據(jù)太長,所以我這里只獲取了北京的數(shù)據(jù)。
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;//會(huì)移動(dòng)的橫線布局private Line line;private Context mContext;//總共tab的數(shù)量private int tabAmount = 3;//當(dāng)前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);}/*** 得到一個(gè)新的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;}/*** 設(shè)置tab的數(shù)量,默認(rèn)3個(gè),不小于2個(gè)* @param tabAmount tab的數(shù)量* */public void setTabAmount(int tabAmount) {if(tabAmount >= 2){this.tabAmount = tabAmount;init(mContext);}elsethrow new RuntimeException("AddressSelector tabAmount can not less-than 2 !");}/*** 設(shè)置列表的點(diǎn)擊事件回調(diào)接口* */public void setOnItemClickListener(OnItemClickListener onItemClickListener) {this.onItemClickListener = onItemClickListener;}/*** 設(shè)置列表的數(shù)據(jù)源,設(shè)置后立即生效* */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");}}/*** 設(shè)置頂部tab的點(diǎn)擊事件回調(diào)* */public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {this.onTabSelectedListener = onTabSelectedListener;}public void onClick(View v) {Tab tab = (Tab) v;//如果點(diǎn)擊的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("");}}}/*** 設(shè)置Tab文字選中的顏色* */public void setTextSelectedColor(int textSelectedColor) {TextSelectedColor = textSelectedColor;}/*** 設(shè)置Tab文字默認(rèn)顏色* */public void setTextEmptyColor(int textEmptyColor) {TextEmptyColor = textEmptyColor;}/*** 設(shè)置Tab橫線的顏色* */public void setLineColor(int lineColor) {line.setSelectedColor(lineColor);}/*** 設(shè)置tab下方分隔線的顏色* */public void setGrayLineColor(int grayLineColor) {grayLine.setBackgroundColor(grayLineColor);}/*** 設(shè)置列表文字大小* */public void setListTextSize(int listTextSize) {this.listTextSize = listTextSize;}/*** 設(shè)置列表文字顏色* */public void setListTextNormalColor(int listTextNormalColor) {this.listTextNormalColor = listTextNormalColor;}/*** 設(shè)置列表選中文字顏色* */public void setListTextSelectedColor(int listTextSelectedColor) {this.listTextSelectedColor = listTextSelectedColor;}/*** 設(shè)置列表icon資源* */public void setListItemIcon(int listItemIcon) {this.listItemIcon = listItemIcon;}/*** 標(biāo)簽控件* */("AppCompatCustomView")public class Tab extends TextView {private int index = 0;private int TextSelectedColor = Color.parseColor("#D5A872");private int TextEmptyColor = Color.parseColor("#333333");/*** 是否選中狀態(tài)* */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中設(shè)置點(diǎn)擊按鈕打開PopWindow進(jìn)行地址選擇
/*** 設(shè)置彈出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);//數(shù)據(jù)解析AddressSelectorReq addressSelectorReq = new Gson().fromJson(String.valueOf(response), AddressSelectorReq.class);//設(shè)置默認(rèn)選擇數(shù)據(jù)dealWithAddressSelector(addressSelector, addressSelectorReq.getDatas(), mPopupWindow);imageBtn.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {mPopupWindow.dismiss();}});break;}}
4、設(shè)置選擇器默認(rèn)數(shù)據(jù)
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);//設(shè)置數(shù)據(jù)addressSelector.setCities(itemAddressReqs);//設(shè)置Tab橫線的顏色addressSelector.setLineColor(Color.parseColor("#D5A872"));//設(shè)置Tab文字默認(rèn)顏色addressSelector.setTextEmptyColor(Color.parseColor("#000000"));//設(shè)置列表選中文字顏色addressSelector.setListTextSelectedColor(Color.parseColor("#D5A872"));//設(shè)置Tab文字選中的顏色addressSelector.setTextSelectedColor(Color.parseColor("#D5A872"));//設(shè)置列表的點(diǎn)擊事件回調(diào)接口addressSelector.setOnItemClickListener(new OnItemClickListener() {public void itemClick(AddressSelector addressSelector, CityInterface city, int tabPosition, int selecePos) {switch (tabPosition) {case 0://設(shè)置省列表數(shù)據(jù)sheng[0] = city.getCityName();saveId[0] = addressSelectorList.get(selecePos).getDb_id();childrenBeanXList = addressSelectorList.get(selecePos).getDb_children();addressSelector.setCities(getItemAddressShi(childrenBeanXList));break;case 1://設(shè)置市列表數(shù)據(jù)sheng[1] = city.getCityName();saveId[1] = childrenBeanXList.get(selecePos).getCb_id();childrenBeans = childrenBeanXList.get(selecePos).getCb_children();addressSelector.setCities(getItemAddressQu(childrenBeans));break;case 2://設(shè)置區(qū)列表數(shù)據(jù)sheng[2] = city.getCityName();saveId[2] = childrenBeans.get(selecePos).getId();text_suozaidiqu.setText(sheng[0] + sheng[1] + sheng[2]);mPopupWindow.dismiss();break;}}});//設(shè)置頂部tab的點(diǎn)擊事件回調(diào)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、將獲取的省市區(qū)的數(shù)據(jù)進(jìn)行分類
/*** 獲取省的數(shù)據(jù)** @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;}/*** 獲取市的數(shù)據(jù)** @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;}/*** 獲取區(qū)的數(shù)據(jù)** @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、設(shè)置地址選擇器的布局文件
<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="所在區(qū)域"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、總結(jié)
到這里就實(shí)現(xiàn)了地址選擇器的功能,因?yàn)楹笈_(tái)提供的地址數(shù)據(jù)可能不一樣,所以這里就不把全部數(shù)據(jù)拿出來了,需要完整數(shù)據(jù)的也可以Q我。
需要Demo的童鞋可以在公眾號(hào)回復(fù) “地址選擇器”
到這里就結(jié)束啦
