Android 自定义仿京东地址选择器
public class AddressPickerViewextends RelativeLayout{
// recyclerView 选中Item 的颜色
private int defaultSelectedColor = ColorparseColor("#3D71FF");
// recyclerView 未选中Item 的颜色
private int defaultUnSelectedColor = ColorparseColor("#2c2c2c");
// 确定字体不可以点击时候的颜色
private int defaultSureUnClickColor = ColorparseColor("#7F7F7F");
// 确定字体可以点击时候的颜色
private int defaultSureCanClickColor = ColorparseColor("#3D71FF");
private ContextmContext;
private int defaultTabCount =3; //tab 的数量
private TabLayoutmTabLayout; // tabLayout
private RecyclerViewmRvList; // 显示数据的RecyclerView
private StringdefaultProvince ="省份"; //显示在上面tab中的省份
private StringdefaultCity ="城市"; //显示在上面tab中的城市
private StringdefaultDistrict ="区县"; //显示在上面tab中的区县
private ListmRvData; // 用来在recyclerview显示的数据
private AddressAdaptermAdapter; // recyclerview 的adapter
private YwpAddressBeanmYwpAddressBean; // 总数据
private YwpAddressBeanAddressItemBeanmSelectProvice; //选中 省份bean
private YwpAddressBeanAddressItemBeanmSelectCity;//选中 城市bean
private YwpAddressBeanAddressItemBeanmSelectDistrict;//选中 区县bean
private int mSelectProvicePosition =0; //选中 省份 位置
private int mSelectCityPosition =0;//选中 城市 位置
private int mSelectDistrictPosition =0;//选中 区县 位置
private OnAddressPickerSureListenermOnAddressPickerSureListener;
public AddressPickerView(Context context) {
super(context);
init(context);
}
public AddressPickerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AddressPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/
初始化
/
private void init(Context context) {
mContext = context;
mRvData =new ArrayList<>();
// UI
View rootView =inflate(mContext, Rlayoutaddress_picker_view, this);
// tablayout初始化
mTabLayout = (TabLayout) rootViewfindViewById(RidtlTabLayout);
mTabLayoutaddTab(mTabLayoutnewTab()setText(defaultProvince));
mTabLayoutaddTab(mTabLayoutnewTab()setText(defaultCity));
mTabLayoutaddTab(mTabLayoutnewTab()setText(defaultDistrict));
mTabLayoutaddOnTabSelectedListener(tabSelectedListener);
// recyclerview adapter的绑定
mRvList = (RecyclerView) rootViewfindViewById(RidrvList);
mRvListsetLayoutManager(new LinearLayoutManager(context));
mAdapter =new AddressAdapter();
mRvListsetAdapter(mAdapter);
// 初始化默认的本地数据 也提供了方法接收外面数据
mRvListpost(new Runnable() {
@Override
public void run() {
initData();
}
});
}
/
初始化数据
拿assets下的json文件
/
private void initData() {
StringBuilder jsonSB =new StringBuilder();
try {
BufferedReader addressJsonStream =new BufferedReader(new InputStreamReader(mContextgetAssets()open("addressjson")));
String line;
while ((line = addressJsonStreamreadLine()) !=null) {
jsonSBappend(line);
}
}catch (IOException e) {
eprintStackTrace();
}
// 将数据转换为对象
mYwpAddressBean =new Gson()fromJson(jsonSBtoString(), YwpAddressBeanclass);
if (mYwpAddressBean !=null) {
mRvDataclear();
mRvDataaddAll(mYwpAddressBeangetProvince());
mAdapternotifyDataSetChanged();
}
}
/
开放给外部传入数据
暂时就用这个Bean模型,如果数据不一致就需要各自根据数据来生成这个bean了
/
public void initData(YwpAddressBean bean) {
if (bean !=null) {
mSelectDistrict =null;
mSelectCity =null;
mSelectProvice =null;
mTabLayoutgetTabAt(0)select();
mYwpAddressBean = bean;
mRvDataclear();
mRvDataaddAll(mYwpAddressBeangetProvince());
mAdapternotifyDataSetChanged();
}
}
//点确定
private void sure() {
if (mSelectProvice !=null &&
mSelectCity !=null &&
mSelectDistrict !=null) {
// 回调接口
if (mOnAddressPickerSureListener !=null) {
mOnAddressPickerSureListeneronSureClick(mSelectProvicegetN(), mSelectCitygetN(), mSelectDistrictgetN());
}
}else {
ToastmakeText(mContext, "地址还没有选完整哦", ToastLENGTH_SHORT)show();
}
}
@Override
protected void onDetachedFromWindow() {
superonDetachedFromWindow();
// mYwpAddressBean = null;
}
/
TabLayout 切换事件
/
TabLayoutOnTabSelectedListenertabSelectedListener =new TabLayoutOnTabSelectedListener() {
@Override
public void onTabSelected(TabLayoutTab tab) {
mRvDataclear();
switch (tabgetPosition()) {
case 0:
mRvDataaddAll(mYwpAddressBeangetProvince());
mAdapternotifyDataSetChanged();
// 滚动到这个位置
mRvListsmoothScrollToPosition(mSelectProvicePosition);
break;
case 1:
// 点到城市的时候要判断有没有选择省份
if (mSelectProvice !=null) {
for (YwpAddressBeanAddressItemBean itemBean :mYwpAddressBeangetCity()) {
if (itemBeangetP()equals(mSelectProvicegetI()))
mRvDataadd(itemBean);
}
}else {
ToastmakeText(mContext, "请您先选择省份", ToastLENGTH_SHORT)show();
}
mAdapternotifyDataSetChanged();
// 滚动到这个位置
mRvListsmoothScrollToPosition(mSelectCityPosition);
break;
case 2:
// 点到区的时候要判断有没有选择省份与城市
if (mSelectProvice !=null &&mSelectCity !=null) {
for (YwpAddressBeanAddressItemBean itemBean :mYwpAddressBeangetDistrict()) {
if (itemBeangetP()equals(mSelectCitygetI()))
mRvDataadd(itemBean);
}
}else {
ToastmakeText(mContext, "请您先选择省份与城市", ToastLENGTH_SHORT)show();
}
mAdapternotifyDataSetChanged();
// 滚动到这个位置
mRvListsmoothScrollToPosition(mSelectDistrictPosition);
break;
}
}
@Override
public void onTabUnselected(TabLayoutTab tab) {
}
@Override
public void onTabReselected(TabLayoutTab tab) {
}
};
/
下面显示数据的adapter
/
class AddressAdapterextends RecyclerViewAdapter {
@Override
public ViewHolderonCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflaterfrom(mContext)inflate(Rlayoutitem_address_text, parent, false));
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final int tabSelectPosition =mTabLayoutgetSelectedTabPosition();
holdermTitlesetText(mRvDataget(position)getN());
holdermTitlesetTextColor(defaultUnSelectedColor);
// 设置选中效果的颜色
switch (tabSelectPosition) {
case 0:
if (mRvDataget(position) !=null &&
mSelectProvice !=null &&
mRvDataget(position)getI()equals(mSelectProvicegetI())) {
holdermTitlesetTextColor(defaultSelectedColor);
}
break;
case 1:
if (mRvDataget(position) !=null &&
mSelectCity !=null &&
mRvDataget(position)getI()equals(mSelectCitygetI())) {
holdermTitlesetTextColor(defaultSelectedColor);
}
break;
case 2:
if (mRvDataget(position) !=null &&
mSelectDistrict !=null &&
mRvDataget(position)getI()equals(mSelectDistrictgetI())) {
holdermTitlesetTextColor(defaultSelectedColor);
}
break;
}
// 设置点击之后的事件
holdermTitlesetOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 点击 分类别
switch (tabSelectPosition) {
case 0:
mSelectProvice =mRvDataget(position);
// 清空后面两个的数据
mSelectCity =null;
mSelectDistrict =null;
mSelectCityPosition =0;
mSelectDistrictPosition =0;
mTabLayoutgetTabAt(1)setText(defaultCity);
mTabLayoutgetTabAt(2)setText(defaultDistrict);
// 设置这个对应的标题
mTabLayoutgetTabAt(0)setText(mSelectProvicegetN());
// 跳到下一个选择
mTabLayoutgetTabAt(1)select();
mSelectProvicePosition =position;
break;
case 1:
mSelectCity =mRvDataget(position);
// 清空后面一个的数据
mSelectDistrict =null;
mSelectDistrictPosition =0;
mTabLayoutgetTabAt(2)setText(defaultDistrict);
// 设置这个对应的标题
mTabLayoutgetTabAt(1)setText(mSelectCitygetN());
// 跳到下一个选择
mTabLayoutgetTabAt(2)select();
mSelectCityPosition =position;
break;
case 2:
mSelectDistrict =mRvDataget(position);
// 没了,选完了,这个时候可以点确定了
mTabLayoutgetTabAt(2)setText(mSelectDistrictgetN());
notifyDataSetChanged();
mSelectDistrictPosition =position;
sure();
break;
}
}
});
}
@Override
public int getItemCount() {
return mRvDatasize();
}
class ViewHolderextends RecyclerViewViewHolder {
TextViewmTitle;
ViewHolder(View itemView) {
super(itemView);
mTitle = (TextView) itemViewfindViewById(RiditemTvTitle);
}
}
}
/
点确定回调这个接口
/
public interface OnAddressPickerSureListener {
void onSureClick(String proviceName,String cityName,String earaName);
}
public void setOnAddressPickerSure(OnAddressPickerSureListener listener) {
thismOnAddressPickerSureListener = listener;
}搜索框功能主要有3部分组成:
ES官方文档建议通过phrase Suggester实行搜索框的自动补全,但这种查询对中文支持不太友好,经常会不做提示;下面我们通过n-gram来实现符合中国人民使用习惯的提示框。
假设有一个词hello,普通建索引时,就是把这个词hello放入倒排索引
用户输入h、he时会找不到索引(倒排索引中只有hello),因此匹配失败
而对于输入即搜索这种应用场景,可以使用一种特殊的n-gram,称为边界n-grams (edge n-grams)
所谓的edge n-gram,就是指它会固定从一边开始,进行窗口滑动,每次滑动长度为1,最终的结果取决于 n 的选择长度
以单词hello为例,它的edge n-gram的结果如下:
因此可以发现到,在使用edge n-gram建索引时,一个单词会生成好几个索引,而这些索引一定是从头开始
这符合了输入即搜索的特性,即是用户打h、he能找到倒排中的索引h、he,而这些索引对应著的数据就是hello
需要注意的是,这里使用fuzziness来模糊匹配提升用户体验,fuzziness=1 允许用户输入一个错别字,并通过prefix_length设置为1来跳过开头首个字符的判断,因为一般用户输入出错大多发生在后面
需要注意:
其中min_word_length是用来控制候选词长度的,这里设置为2,意思是当term长度>=2才会被显示;
prefix_length=1表示忽略首字符是错别字,大多数输入错别字发生在后面;
min_doc_freq 当建议词出现文档频率低于该值时将被忽略,线上可适当调大该值以提升搜索效果
易企秀商城
// recyclerView 选中Item 的颜色
private int defaultSelectedColor = ColorparseColor("#3D71FF");
// recyclerView 未选中Item 的颜色
private int defaultUnSelectedColor = ColorparseColor("#2c2c2c");
// 确定字体不可以点击时候的颜色
private int defaultSureUnClickColor = ColorparseColor("#7F7F7F");
// 确定字体可以点击时候的颜色
private int defaultSureCanClickColor = ColorparseColor("#3D71FF");
private ContextmContext;
private int defaultTabCount =3; //tab 的数量
private TabLayoutmTabLayout; // tabLayout
private RecyclerViewmRvList; // 显示数据的RecyclerView
private StringdefaultProvince ="省份"; //显示在上面tab中的省份
private StringdefaultCity ="城市"; //显示在上面tab中的城市
private StringdefaultDistrict ="区县"; //显示在上面tab中的区县
private ListmRvData; // 用来在recyclerview显示的数据
private AddressAdaptermAdapter; // recyclerview 的adapter
private YwpAddressBeanmYwpAddressBean; // 总数据
private YwpAddressBeanAddressItemBeanmSelectProvice; //选中 省份bean
private YwpAddressBeanAddressItemBeanmSelectCity;//选中 城市bean
private YwpAddressBeanAddressItemBeanmSelectDistrict;//选中 区县bean
private int mSelectProvicePosition =0; //选中 省份 位置
private int mSelectCityPosition =0;//选中 城市 位置
private int mSelectDistrictPosition =0;//选中 区县 位置
private OnAddressPickerSureListenermOnAddressPickerSureListener;
public AddressPickerView(Context context) {
super(context);
init(context);
}
public AddressPickerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AddressPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/
初始化
/
private void init(Context context) {
mContext = context;
mRvData =new ArrayList<>();
// UI
View rootView =inflate(mContext, Rlayoutaddress_picker_view, this);
// tablayout初始化
mTabLayout = (TabLayout) rootViewfindViewById(RidtlTabLayout);
mTabLayoutaddTab(mTabLayoutnewTab()setText(defaultProvince));
mTabLayoutaddTab(mTabLayoutnewTab()setText(defaultCity));
mTabLayoutaddTab(mTabLayoutnewTab()setText(defaultDistrict));
mTabLayoutaddOnTabSelectedListener(tabSelectedListener);
// recyclerview adapter的绑定
mRvList = (RecyclerView) rootViewfindViewById(RidrvList);
mRvListsetLayoutManager(new LinearLayoutManager(context));
mAdapter =new AddressAdapter();
mRvListsetAdapter(mAdapter);
// 初始化默认的本地数据 也提供了方法接收外面数据
mRvListpost(new Runnable() {
@Override
public void run() {
initData();
}
});
}
/
初始化数据
拿assets下的json文件
/
private void initData() {
StringBuilder jsonSB =new StringBuilder();
try {
BufferedReader addressJsonStream =new BufferedReader(new InputStreamReader(mContextgetAssets()open("addressjson")));
String line;
while ((line = addressJsonStreamreadLine()) !=null) {
jsonSBappend(line);
}
}catch (IOException e) {
eprintStackTrace();
}
// 将数据转换为对象
mYwpAddressBean =new Gson()fromJson(jsonSBtoString(), YwpAddressBeanclass);
if (mYwpAddressBean !=null) {
mRvDataclear();
mRvDataaddAll(mYwpAddressBeangetProvince());
mAdapternotifyDataSetChanged();
}
}
/
开放给外部传入数据
暂时就用这个Bean模型,如果数据不一致就需要各自根据数据来生成这个bean了
/
public void initData(YwpAddressBean bean) {
if (bean !=null) {
mSelectDistrict =null;
mSelectCity =null;
mSelectProvice =null;
mTabLayoutgetTabAt(0)select();
mYwpAddressBean = bean;
mRvDataclear();
mRvDataaddAll(mYwpAddressBeangetProvince());
mAdapternotifyDataSetChanged();
}
}
//点确定
private void sure() {
if (mSelectProvice !=null &&
mSelectCity !=null &&
mSelectDistrict !=null) {
// 回调接口
if (mOnAddressPickerSureListener !=null) {
mOnAddressPickerSureListeneronSureClick(mSelectProvicegetN(), mSelectCitygetN(), mSelectDistrictgetN());
}
}else {
ToastmakeText(mContext, "地址还没有选完整哦", ToastLENGTH_SHORT)show();
}
}
@Override
protected void onDetachedFromWindow() {
superonDetachedFromWindow();
// mYwpAddressBean = null;
}
/
TabLayout 切换事件
/
TabLayoutOnTabSelectedListenertabSelectedListener =new TabLayoutOnTabSelectedListener() {
@Override
public void onTabSelected(TabLayoutTab tab) {
mRvDataclear();
switch (tabgetPosition()) {
case 0:
mRvDataaddAll(mYwpAddressBeangetProvince());
mAdapternotifyDataSetChanged();
// 滚动到这个位置
mRvListsmoothScrollToPosition(mSelectProvicePosition);
break;
case 1:
// 点到城市的时候要判断有没有选择省份
if (mSelectProvice !=null) {
for (YwpAddressBeanAddressItemBean itemBean :mYwpAddressBeangetCity()) {
if (itemBeangetP()equals(mSelectProvicegetI()))
mRvDataadd(itemBean);
}
}else {
ToastmakeText(mContext, "请您先选择省份", ToastLENGTH_SHORT)show();
}
mAdapternotifyDataSetChanged();
// 滚动到这个位置
mRvListsmoothScrollToPosition(mSelectCityPosition);
break;
case 2:
// 点到区的时候要判断有没有选择省份与城市
if (mSelectProvice !=null &&mSelectCity !=null) {
for (YwpAddressBeanAddressItemBean itemBean :mYwpAddressBeangetDistrict()) {
if (itemBeangetP()equals(mSelectCitygetI()))
mRvDataadd(itemBean);
}
}else {
ToastmakeText(mContext, "请您先选择省份与城市", ToastLENGTH_SHORT)show();
}
mAdapternotifyDataSetChanged();
// 滚动到这个位置
mRvListsmoothScrollToPosition(mSelectDistrictPosition);
break;
}
}
@Override
public void onTabUnselected(TabLayoutTab tab) {
}
@Override
public void onTabReselected(TabLayoutTab tab) {
}
};
/
下面显示数据的adapter
/
class AddressAdapterextends RecyclerViewAdapter {
@Override
public ViewHolderonCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflaterfrom(mContext)inflate(Rlayoutitem_address_text, parent, false));
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final int tabSelectPosition =mTabLayoutgetSelectedTabPosition();
holdermTitlesetText(mRvDataget(position)getN());
holdermTitlesetTextColor(defaultUnSelectedColor);
// 设置选中效果的颜色
switch (tabSelectPosition) {
case 0:
if (mRvDataget(position) !=null &&
mSelectProvice !=null &&
mRvDataget(position)getI()equals(mSelectProvicegetI())) {
holdermTitlesetTextColor(defaultSelectedColor);
}
break;
case 1:
if (mRvDataget(position) !=null &&
mSelectCity !=null &&
mRvDataget(position)getI()equals(mSelectCitygetI())) {
holdermTitlesetTextColor(defaultSelectedColor);
}
break;
case 2:
if (mRvDataget(position) !=null &&
mSelectDistrict !=null &&
mRvDataget(position)getI()equals(mSelectDistrictgetI())) {
holdermTitlesetTextColor(defaultSelectedColor);
}
break;
}
// 设置点击之后的事件
holdermTitlesetOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 点击 分类别
switch (tabSelectPosition) {
case 0:
mSelectProvice =mRvDataget(position);
// 清空后面两个的数据
mSelectCity =null;
mSelectDistrict =null;
mSelectCityPosition =0;
mSelectDistrictPosition =0;
mTabLayoutgetTabAt(1)setText(defaultCity);
mTabLayoutgetTabAt(2)setText(defaultDistrict);
// 设置这个对应的标题
mTabLayoutgetTabAt(0)setText(mSelectProvicegetN());
// 跳到下一个选择
mTabLayoutgetTabAt(1)select();
mSelectProvicePosition =position;
break;
case 1:
mSelectCity =mRvDataget(position);
// 清空后面一个的数据
mSelectDistrict =null;
mSelectDistrictPosition =0;
mTabLayoutgetTabAt(2)setText(defaultDistrict);
// 设置这个对应的标题
mTabLayoutgetTabAt(1)setText(mSelectCitygetN());
// 跳到下一个选择
mTabLayoutgetTabAt(2)select();
mSelectCityPosition =position;
break;
case 2:
mSelectDistrict =mRvDataget(position);
// 没了,选完了,这个时候可以点确定了
mTabLayoutgetTabAt(2)setText(mSelectDistrictgetN());
notifyDataSetChanged();
mSelectDistrictPosition =position;
sure();
break;
}
}
});
}
@Override
public int getItemCount() {
return mRvDatasize();
}
class ViewHolderextends RecyclerViewViewHolder {
TextViewmTitle;
ViewHolder(View itemView) {
super(itemView);
mTitle = (TextView) itemViewfindViewById(RiditemTvTitle);
}
}
}
/
点确定回调这个接口
/
public interface OnAddressPickerSureListener {
void onSureClick(String proviceName,String cityName,String earaName);
}
public void setOnAddressPickerSure(OnAddressPickerSureListener listener) {
thismOnAddressPickerSureListener = listener;
}搜索框功能主要有3部分组成:
ES官方文档建议通过phrase Suggester实行搜索框的自动补全,但这种查询对中文支持不太友好,经常会不做提示;下面我们通过n-gram来实现符合中国人民使用习惯的提示框。
假设有一个词hello,普通建索引时,就是把这个词hello放入倒排索引
用户输入h、he时会找不到索引(倒排索引中只有hello),因此匹配失败
而对于输入即搜索这种应用场景,可以使用一种特殊的n-gram,称为边界n-grams (edge n-grams)
所谓的edge n-gram,就是指它会固定从一边开始,进行窗口滑动,每次滑动长度为1,最终的结果取决于 n 的选择长度
以单词hello为例,它的edge n-gram的结果如下:
因此可以发现到,在使用edge n-gram建索引时,一个单词会生成好几个索引,而这些索引一定是从头开始
这符合了输入即搜索的特性,即是用户打h、he能找到倒排中的索引h、he,而这些索引对应著的数据就是hello
需要注意的是,这里使用fuzziness来模糊匹配提升用户体验,fuzziness=1 允许用户输入一个错别字,并通过prefix_length设置为1来跳过开头首个字符的判断,因为一般用户输入出错大多发生在后面
需要注意:
其中min_word_length是用来控制候选词长度的,这里设置为2,意思是当term长度>=2才会被显示;
prefix_length=1表示忽略首字符是错别字,大多数输入错别字发生在后面;
min_doc_freq 当建议词出现文档频率低于该值时将被忽略,线上可适当调大该值以提升搜索效果
易企秀商城
0条评论