Android仿京东实现地址选择功能
龙旋
共 24505字,需浏览 50分钟
·
2021-03-07 08:47
最近在做地址管理的功能,新建地址的时候,需要根据后台提供的省市区的数据,让用户进行地址的选择,最近项目比较赶,本来想网上找一个的,可是找了很久都没找到我想要的效果,所以就根据后台提供的数据,弄了一个。
实现流程:
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的外层layout
private 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);
}
else
throw 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);
else
onTabSelectedListener.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);
else
setTextColor(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
*/
@NonNull
private 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
*/
@NonNull
private 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
*/
@NonNull
private 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">
<ImageView
android: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" />
<TextView
android: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.AddressSelector
android:id="@+id/address"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="70dp" />
</RelativeLayout>
7、总结
到这里就实现了地址选择器的功能,因为后台提供的地址数据可能不一样,所以这里就不把全部数据拿出来了,需要完整数据的也可以Q我。
需要Demo的童鞋可以在公众号回复 “地址选择器”
到这里就结束啦
评论