wordpress migrate.min.js是什么,网站快速优化排名推荐,汽车营销策划方案,网站开发技术考试试卷前言
做了一个仿拼多多的地址选择器#xff0c;但是与拼多多实现方法有些出入#xff0c;大体效果是差不多的。废话不多说#xff0c;先上一张效果动图#xff1a; 开始
先说说本文的一些概念。地区级别#xff1a;就是比如省级#xff0c;市级#xff0c;县级#x…前言
做了一个仿拼多多的地址选择器但是与拼多多实现方法有些出入大体效果是差不多的。废话不多说先上一张效果动图 开始
先说说本文的一些概念。地区级别就是比如省级市级县级镇级那么这种最多就是4级。好了我们分析一波效果图当一个级别的地区选择好之后会创建出一个新的Tab到了最后一个地区级别之后就不会再创建新的。如果倒回去重新选择一个级别的地区会移除后面的Tab之后再创建一个新的Tab。选择好之后如果点击Tab会切换到相应地区级别并且滚动到之前选择的地区显示创建新的Tab就默认滚动到第一个position的位置。其次来看看我们这个界面的布局
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoandroid:layout_widthmatch_parentandroid:layout_height560dpandroid:orientationverticalandroid:paddingStart12dpandroid:paddingEnd12dp!-- Dialog的标题 --TextViewandroid:idid/user_tv_dialog_titleandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTop18dpandroid:layout_gravitycenter_horizontal/!-- 标题下的第一条横线 --Viewandroid:layout_widthmatch_parentandroid:layout_height1dpandroid:background#e6e6e6android:layout_marginTop17dp/!-- 顶部的TabLayout --android.support.design.widget.TabLayoutandroid:idid/user_tb_dialog_tabandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentapp:tabSelectedTextColorcolor/colorPrimaryapp:tabGravityfillapp:tabModescrollable/!-- TabLayout下方的横线 --Viewandroid:layout_widthmatch_parentandroid:layout_height1dpandroid:background#e6e6e6/!-- 显示地区数据的RecyclerView --android.support.v7.widget.RecyclerViewandroid:idid/user_rv_dialog_listandroid:layout_widthmatch_parentandroid:layout_height0dpandroid:layout_weight1/
/LinearLayout从布局中我们可以看出我最主要靠TabLayout加RecyclerView实现这个效果而拼多多个人猜测是TabLayout加RecyclerView加ViewPager所以拼多多的RecyclerView是可以侧滑到上一个Tab页或下一个这也就是和拼多多效果的不同之处。
开始撸代码
从代码下手首先把单个地区列表的布局写好
?xml version1.0 encodingutf-8?
LinearLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:orientationhorizontalandroid:paddingTop10dpandroid:paddingBottom10dptools:ignoreUseCompoundDrawables!-- 显示地区名称 --TextViewandroid:idid/user_tv_address_dialogandroid:layout_widthwrap_contentandroid:layout_heightwrap_content/!-- 显示后面的勾选图标 --ImageViewandroid:idid/user_iv_address_dialogandroid:layout_width13dpandroid:layout_height9dpandroid:srcdrawable/user_icon_address_checkandroid:layout_marginStart11dpandroid:layout_gravitycenter_verticalandroid:visibilitygonetools:ignoreContentDescription /
/LinearLayout把地区这个实体对象创建好
public class AddressItem {// 地区名private String address;// 是否勾选private boolean isChecked;// 地区的ID我这边项目需要的是int型大家可以根据自己项目需要进行修改private int id;public String getAddress() {return this.address;}public void setAddress(String address) {this.address address;}public boolean isChecked() {return this.isChecked;}public void setChecked(boolean checked) {this.isChecked checked;}public int getId() {return this.id;}public void setId(int id) {this.id id;}Overridepublic String toString() {return AddressItem{ address address \ , isChecked isChecked , id id };}
}把RecyclerView的适配器写好
public class AddressAdapter extends RecyclerView.AdapterAddressAdapter.MyViewHolder {// 保存地区数据的列表private ListAddressItem list new ArrayList();// 自定义的单项被点击监听事件private ItemClickListener listener;NonNullOverridepublic MyViewHolder onCreateViewHolder(NonNull ViewGroup viewGroup, int i) {View view LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.user_item_address_bottom_sheet_dialog, viewGroup, false);return new MyViewHolder(view);}Overridepublic void onBindViewHolder(NonNull MyViewHolder myViewHolder, int i) {AddressItem item list.get(i);if (item.isChecked()) {myViewHolder.tvAddress.setText(item.getAddress());myViewHolder.tvAddress.setTextColor(Color.parseColor(#1F83FF));myViewHolder.ivChecked.setVisibility(View.VISIBLE);} else {myViewHolder.tvAddress.setText(item.getAddress());myViewHolder.tvAddress.setTextColor(Color.BLACK);myViewHolder.ivChecked.setVisibility(View.GONE);}}Overridepublic int getItemCount() {return this.list null ? 0 : list.size();}public void setList(ListAddressItem list) {if (this.list ! null list ! null) {this.list.clear();this.list.addAll(list);this.notifyDataSetChanged();}}public void setOnItemClickListener(NonNull ItemClickListener listener) {this.listener listener;}class MyViewHolder extends RecyclerView.ViewHolder {TextView tvAddress;ImageView ivChecked;MyViewHolder(NonNull View itemView) {super(itemView);tvAddress itemView.findViewById(R.id.user_tv_address_dialog);ivChecked itemView.findViewById(R.id.user_iv_address_dialog);if (listener ! null) {itemView.setOnClickListener(v - listener.onItemClick(getAdapterPosition()));}}}public interface ItemClickListener {void onItemClick(int position);}
}首先自己动手写了两个BaseDialog没什么营养代码也很简单
public abstract class CustomBaseDialog extends Dialog {protected Context context;public CustomBaseDialog(NonNull Context context) {super(context);this.context context;}protected abstract Integer getLayout();protected abstract Integer getGravity();protected abstract Integer getBackgroundRes();protected abstract Integer getWindowAnimations();protected abstract void initView();Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getLayout() ! null)setContentView(getLayout());Window window getWindow();if (window ! null) {// 去除DecorView默认的内边距好让布局占满整个横向屏幕View decorView window.getDecorView();decorView.setPadding(0,0,0,0);if (getGravity() ! null)window.setGravity(getGravity());elsewindow.setGravity(Gravity.CENTER);if (getWindowAnimations() ! null)window.setWindowAnimations(getWindowAnimations());if (getBackgroundRes() ! null)decorView.setBackgroundResource(getBackgroundRes());}initView();}protected void setClickListener(int id, View.OnClickListener listener) {findViewById(id).setOnClickListener(listener);}
}public abstract class CustomBaseBottomSheetDialog extends CustomBaseDialog {public CustomBaseBottomSheetDialog(NonNull Context context) {super(context);}Overrideprotected Integer getGravity() {return Gravity.BOTTOM;}Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Window window getWindow();if (null ! window) {// 去除window的margin目的也是为了让布局占满屏幕WindowManager.LayoutParams layoutParams window.getAttributes();layoutParams.width WindowManager.LayoutParams.MATCH_PARENT;layoutParams.horizontalMargin 0;window.setAttributes(layoutParams);}}
}接着才是重点自定义地址选择器Dialog
public class AddressBottomSheetDialog extends CustomBaseBottomSheetDialog {private TabLayout tabLayout;private AddressAdapter addressAdapter;private int maxLevel; // 最大有多少级的地区可以通过setMaxLevel方法进行自定义private SparseArrayListAddressItem levelList; // 级别列表数据private SparseIntArray levelPosition; // 各个级别选中的列表positionprivate SparseIntArray levelIds; // 各个级别选择的地址IDprivate String title; // 标题private String tabText 请选择; // 新的Tab默认显示的文本private TabSelectChangeListener changeListener; // Tab的选择被改变的监听public AddressBottomSheetDialog(NonNull Context context) {super(context);}Overrideprotected Integer getLayout() {return R.layout.user_layout_address_bottom_sheet_dialog;}Overrideprotected Integer getBackgroundRes() {return R.drawable.bg_dialog_bottom;}Overrideprotected Integer getWindowAnimations() {return R.style.DialogBottom;}Overrideprotected void initView() {levelList new SparseArray();levelPosition new SparseIntArray();levelIds new SparseIntArray();((TextView)findViewById(R.id.user_tv_dialog_title)).setText(title);tabLayout findViewById(R.id.user_tb_dialog_tab);final RecyclerView recyclerView findViewById(R.id.user_rv_dialog_list);tabLayout.addOnTabSelectedListener(new TabLayout.BaseOnTabSelectedListener() {Overridepublic void onTabSelected(TabLayout.Tab tab) {final int position tab.getPosition();ListAddressItem list levelList.get(position);if (null ! list !list.isEmpty()) { // 如果选中级别的List没有数据就通过执行回调来获取否则直接复用addressAdapter.setList(list);final int lastClickPositon levelPosition.get(position, -1); // 获取上一次选中的地区的position如果找不到默认返回-1if (lastClickPositon 0) recyclerView.smoothScrollToPosition(lastClickPositon); // 如果上一次有选择RecyclerView滚动到指定position} else if (changeListener ! null) {changeListener.onSelectChange(position, levelIds.get(position));}}Overridepublic void onTabUnselected(TabLayout.Tab tab) {}Overridepublic void onTabReselected(TabLayout.Tab tab) {}});addressAdapter new AddressAdapter();// 列表单项点击事件addressAdapter.setOnItemClickListener(position - {final int selectedTabPosition tabLayout.getSelectedTabPosition(); // 选中的Tab的positionlevelIds.put(selectedTabPosition, levelList.get(selectedTabPosition).get(position).getId()); // 更新选中的地区的IDchangeSelect(selectedTabPosition, position);levelPosition.put(selectedTabPosition, position); // 更新选中的地区在列表中的positionsetTabText(selectedTabPosition, levelList.get(selectedTabPosition).get(position).getAddress()); // 将选中的地区的名字显示在Tab上if (selectedTabPosition maxLevel - 1 selectedTabPosition tabLayout.getTabCount() - 1) { // 如果没达到MaxLevel并且选中的Tab是最后一个就添加一个Tab并且RecyclerView滚动到最顶部tabLayout.addTab(createTab(), true);recyclerView.smoothScrollToPosition(0);}});recyclerView.setLayoutManager(new LinearLayoutManager(context));recyclerView.setAdapter(addressAdapter);tabLayout.addTab(createTab(), true); // 默认添加一个Tab}// 创建一个请选择的tab并返回private TabLayout.Tab createTab() {return tabLayout.newTab().setText(tabText);}// 当点击了RecyclerView条目的时候执行的方法private void changeSelect(int selectedTabPosition, int nowClickPosition) {// 保存下来的当前列表上一个点击位置.如果找不到该值默认返回-1final int lastPosition levelPosition.get(selectedTabPosition, -1);// 如果上一个点击位置和下一个点击位置相同则不做改变if (nowClickPosition lastPosition) {return;}// 如果不是最后一个并且又重新选择了级别地区移除后面的Tabfinal int count tabLayout.getTabCount();// 这里要倒过来移除Tab不然会出现这样的情况假如你有四个Tab你移除第0个接着移除第一个的话第一个不是原来的第一个。因为你把第0个移除原来的第一个就到了第0个的位置上。所以倒过来移除是明智的做法if (selectedTabPosition count - 1) {TabLayout.Tab nowTab tabLayout.getTabAt(selectedTabPosition);if (null ! nowTab) nowTab.setText(tabText);for (int i count - 1; i selectedTabPosition; i--) {// 将相应地区级别的列表数据移除levelList.remove(i);// 将之前选中的position重置为-1levelPosition.put(i, -1);// 将之前记录的地区ID重置为-1levelIds.put(i, -1);tabLayout.removeTabAt(i);}}// 将现在选择的地区设置为已经选中levelList.get(selectedTabPosition).get(nowClickPosition).setChecked(true);// 通过adapter更新列表单个对象addressAdapter.notifyItemChanged(nowClickPosition);if (lastPosition 0) {// 将上一个选中的地区标记为未选中levelList.get(selectedTabPosition).get(lastPosition).setChecked(false);// 通过adapter更新列表单个对象addressAdapter.notifyItemChanged(lastPosition);}}// 设置第几个tab的文字private void setTabText(int tabPosition, String text) {TabLayout.Tab tab tabLayout.getTabAt(tabPosition);if (null ! tab) tab.setText(text);}// ----------------------------- 以下是对外公开方法与接口 --------------------------/*** 设置Dialog的标题* param title 标题文字*/public void setDialogTitle(String title) {this.title title;}/*** 设置在当前tab下还未选择区域时候tab默认显示的文字* param tabDefaultText 默认显示的文字*/public void setTabDefaultText(String tabDefaultText) {this.tabText tabDefaultText;}/*** 设置地址最大级别如省市县镇的话就是最大4级* param level 最大级别*/public void setMaxLevel(int level) {this.maxLevel level;}/*** 设置当前级别列表需要显示的列表数据* param list 列表数据* param level 地区级别*/public void setCurrentAddressList(ListAddressItem list, int level) {levelList.put(level, list);addressAdapter.setList(list);}/*** 设置Dialog中Tab点击切换的监听* param listener tab切换监听实现*/public void setTabSelectChangeListener(NonNull TabSelectChangeListener listener) {this.changeListener listener;}/*** 自定义的Tab切换监听接口*/public interface TabSelectChangeListener {void onSelectChange(int level, int parentId);}
}使用方法
private void init() {mDialog new AddressBottomSheetDialog(this);mDialog.setDialogTitle(配送至);mDialog.setMaxLevel(4);mDialog.setTabDefaultText(请选择);mDialog.setTabSelectChangeListener((level, parentId) -mDialog.setCurrentAddressList(requestAddress(level, parentId), level));binding.userIvSelectAddress.setOnClickListener(v - mDialog.show());
}
private ListAddressItem requestAddress(int level, int parentID) {ListAddressItem list new ArrayList();String levelTxt 未知;switch (level) {case 0:levelTxt 省级;break;case 1:levelTxt 市级;break;case 2:levelTxt 县级;break;case 3:levelTxt 镇级;}for (int i 0; i 32; i) {AddressItem item new AddressItem();item.setChecked(false);item.setAddress(levelTxt i);list.add(item);}return list;
}