文章目录

  • 上效果图
  • 逻辑骨架
  • 赋予UI
    • UI封装
    • quick_search_layout.xml
    • item_ordered_list.xml
  • 使用

Android有自带的下拉选择控件Spinner。问题是,一旦候选条目数过多,从中进行选择就很不友好。

解决这个问题常用的一种方式是:引入一个输入,根据输入过滤出部分结果数据。当然,这样做的前提是,需要为每一个数据项设置一个检索标识。

对于一个输入,判断每一条原始数据的检索标识,是否符合既定的匹配规则(比如前缀或者包含匹配的方式),从而得出符合过滤规则的数据结果。

上效果图

逻辑骨架

先来定义控件的逻辑功能部分,核心是根据当前的输入字符串过滤出结果数据,实现见doFilter(String prefix)方法。

/*** UI控件,快速检索* - 可对原始数据进行快速筛选,筛选结果展示到列表里面** @param <T> 需要筛选的数据条目类型* @author Liberg* @Date 2021年11月15日*/
public abstract class QuickSearch<T> {private static final String TAG = "QuickSearch";/*** 原始数据*/private ArrayList<T> originList;/*** 过滤后的数据*/private ArrayList<T> filteredList;public QuickSearch(ArrayList<T> datas) {this.originList = datas;}/*** 抽象方法:从数据item中拿到检索标识*/protected abstract String getSearchLabel(T item);/*** 抽象方法:从数据item中拿到显示名称*/protected abstract String getItemName(T item);/*** 过滤规则:* 1. 只输入1~2个字符时,前缀匹配* 2. 输入>=3个字符时,包含匹配*/public ArrayList<T> doFilter(String prefix) {ArrayList<T> result = new ArrayList<>();if (prefix.length() <= 2) {for (T d : originList) {String label = getSearchLabel(d);if (label != null && label.startsWith(prefix)) {result.add(d);}}} else {for (T d : originList) {String label = getSearchLabel(d);if (label != null && label.indexOf(prefix) >= 0) {result.add(d);}}}return result;}
}

赋予UI

要做一个完整Android控件,离不开对UI部分的封装。

UI封装

public abstract class QuickSearch<T> {private boolean isAttachedToParent = false;private Activity rootActiviy = null;private View containerView = null;private ImageButton ibClose = null;private EditText etLabel = null;private ListView listView = null;private MyAdapter listAdapter = null;OnQuickSearchListener<T> listener = null;public void initUI(Activity rootActivity) {this.rootActiviy = rootActivity;containerView = rootActivity.getLayoutInflater().inflate(R.layout.quick_search_layout, null);ibClose = containerView.findViewById(R.id.ibClose);etLabel = containerView.findViewById(R.id.etLabel);listView = containerView.findViewById(R.id.list);filteredList = originList;listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {if (listener != null) {listener.onItemSelected(filteredList.get(position));}hide();}});listAdapter = new MyAdapter(rootActivity);listView.setAdapter(listAdapter);etLabel.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {filteredList = s.length() == 0 ? originList : doFilter(s.toString());if (listAdapter != null) {listAdapter.notifyDataSetChanged();}}@Overridepublic void afterTextChanged(Editable s) {}});etLabel.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {if (!hasFocus) {UIUtils.hideInputMethod(v);}}});ibClose.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {hide();if (listener != null) {listener.onCancelled();}}});}public void show() {if (containerView == null) return;if (!isAttachedToParent) {Window win = rootActiviy.getWindow();WindowManager.LayoutParams wlp = win.getAttributes();wlp.gravity = Gravity.TOP;win.setAttributes(wlp);win.addContentView(containerView, wlp);isAttachedToParent = true;}containerView.setVisibility(View.VISIBLE);}public void hide() {if (isAttachedToParent) {containerView.setVisibility(View.INVISIBLE);}}/*** 控件对外暴露的事件* @param <T>*/public interface OnQuickSearchListener<T> {void onItemSelected(T item);void onCancelled();}public void setOnQuickSearchListener(OnQuickSearchListener<T> listener) {this.listener = listener;}public void resetDatas(ArrayList<T> datas) {this.originList = datas;filteredList = datas;etLabel.setText("");listAdapter.notifyDataSetChanged();}/*** 控件内部列表使用的数据适配器*/private class MyAdapter extends BaseAdapter {private LayoutInflater mInflater;public MyAdapter(Context context) {mInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return filteredList.size();}@Overridepublic T getItem(int index) {return filteredList.get(index);}@Overridepublic long getItemId(int arg0) {return arg0;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {T item = getItem(position);if (item == null)return null;ViewHolder holder = null;if (convertView == null) {holder = new ViewHolder();convertView = mInflater.inflate(R.layout.item_ordered_list, null);holder.tvIndex = convertView.findViewById(R.id.tvIndex);holder.tvTitle = convertView.findViewById(R.id.tvTitle);holder.tvSubTitle = convertView.findViewById(R.id.tvSubTitle);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.tvIndex.setText("" + (position + 1));holder.tvTitle.setText(getItemName(item));holder.tvSubTitle.setText(getSearchLabel(item));return convertView;}public final class ViewHolder {public TextView tvIndex;public TextView tvTitle;public TextView tvSubTitle;}}
}

其中有2个xml布局文件:

quick_search_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/transparent_40p"android:padding="@dimen/dp15"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:padding="5dp"android:background="#fff"><ImageButtonandroid:id="@+id/ibClose"android:layout_width="40dp"android:layout_height="40dp"android:layout_alignParentRight="true"android:padding="@dimen/dp5"android:background="@color/transparent"android:src="@drawable/ic_close"/><LinearLayoutandroid:id="@+id/llTop"android:paddingEnd="45dp"android:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/etLabel"android:layout_width="match_parent"android:layout_height="40dp"android:layout_toLeftOf="@+id/ibClose"android:background="@drawable/selector_input"android:hint="请输入查询标识进行过滤"android:paddingStart="@dimen/dp5"android:inputType="text"android:singleLine="true"android:textSize="@dimen/f15" /></LinearLayout></RelativeLayout><ListViewandroid:id="@+id/list"android:background="@color/gray2"android:layout_width="match_parent"android:layout_height="match_parent"></ListView>
</LinearLayout>

item_ordered_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:gravity="center"android:paddingTop="8dp"android:paddingBottom="8dp"><TextViewandroid:id="@+id/tvIndex"android:layout_width="36dp"android:layout_height="wrap_content"android:gravity="center"android:text="1000" /><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><TextViewandroid:id="@+id/tvTitle"android:textSize="@dimen/dp18"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="left"android:text="" /><TextViewandroid:id="@+id/tvSubTitle"android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="@color/t3"android:gravity="left"android:text="" /></LinearLayout>
</LinearLayout>

使用

Activity中初始化控件,调用show()/hide()来显示/隐藏控件。

private QuickSearch<XxxData> quickSearch = null;
private void initQuickSearch(ArrayList<XxxData> dealers) {final Activity rootActivity = this;if(quickSearch == null) {quickSearch = new QuickSearch<XxxData>(dealers) {@Overrideprotected String getSearchLabel(XxxData item) {return item.markId;}@Overrideprotected String getItemName(XxxData item) {return item.name;}};quickSearch.initUI(rootActivity);quickSearch.setOnQuickSearchListener(new QuickSearch.OnQuickSearchListener<XxxData>() {@Overridepublic void onItemSelected(XxxData item) {//当前选中了数据item}@Overridepublic void onCancelled() {Log.d(TAG, "onCancelled: initQuickSearch()");}});}
}
quickSearch.show();
quickSearch.hide();

自定义android控件:快速检索QuickSearch相关推荐

  1. 自定义android控件EditText 自定义边框 背景

    自定义EditText边框背景: 首先重新定义一个style.在values文件夹下新建一个xml文件: <?xml version="1.0" encoding=" ...

  2. android+高仿+日历,android高仿钉钉和小米的自定义日历控件(支持阴历和阳历,左右无限翻页viewpager)...

    收藏 0 简介 这是一个高仿钉钉和小米的日历控件,支持快速滑动,界面缓存.想要定制化UI,使用起来非常简单,就像使用ListView一样 一些特点: 可以自定义日历控件UI 支持快速滑动 支持农历和阳 ...

  3. Android 手机卫士--自定义组合控件构件布局结构

    由于设置中心条目中的布局都很类似,所以可以考虑使用自定义组合控件来简化实现 本文地址:http://www.cnblogs.com/wuyudong/p/5909043.html,转载请注明源地址. ...

  4. Android View体系(十)自定义组合控件

    相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...

  5. Android中通过自定义签名控件实现手写签名

    场景 实现手写签名并获取签名照片 注: 博客: BADAO_LIUMANG_QIZHI的博客_霸道流氓气质_CSDN博客-C#,SpringBoot,架构之路领域博主 关注公众号 霸道的程序猿 获取编 ...

  6. android程序日历layout,Android使用GridLayout绘制自定义日历控件

    效果图 思路:就是先设置Gridlayout的行列数,然后往里面放置一定数目的自定义日历按钮控件,最后实现日历逻辑就可以了. 步骤: 第一步:自定义日历控件(初步) 第二步:实现自定义单个日期按钮控件 ...

  7. Android自定义组合控件--EditText和Button组合成带有清空EditText内容功能的复合控件

    目标:实现EditText和Button组合成带有清空EditText内容功能的复合控件,可以通过代码设置自定义控件的相关属性. 实现效果为: (1)在res/layout目录下编写自定义组合控件的布 ...

  8. Android自定义组合布局,Android 流式布局 + 自定义组合控件

    自定义组合控件 package yanjupeng.bawei.com.day09.two; import android.content.Context; import android.util.A ...

  9. Android 自定义组合控件小结

    Android 自定义组合控件小结 引言 接触Android UI开发的这段时间以来,对自定义组合控件有了一定的了解,为此小结一下,本文小结内容主要讨论的是如何使用Android SDK提供的布局和控 ...

最新文章

  1. rdd与mysql表 join_6、JdbcRDD读取mysql的数据
  2. 科大奥锐思考题_科大奥锐光电效应测普朗克常数
  3. Java调用跟踪系统_Tracer:在分布式系统中的调用跟踪和日志相关
  4. Python处理海量手机号码
  5. php来源德育管理系统,西安交通大学城市学院学生服务中心互联网学生工作管理系统...
  6. 易语言文件夹加密解密助手
  7. 腾讯出了一款AI产品,早期癌症筛查准确率最高达90%
  8. 邯郸百亿斤粮食生产 国稻种芯·中国水稻节:河北大市粮食经
  9. python数字转英文_python:将数字转换成用英文表达的程序 | 学步园
  10. Android多媒体框架(5)—— MediaMuxer.jara源码分析
  11. Python3 - pillow的基本用法(第三天)
  12. Bootstrap级联下拉菜单,你肯定用得到
  13. fairyGUI的学习记录2
  14. 官方发布!2021下半年二建考试报名注意事项!
  15. DSC测试仪器校正及检验
  16. 图论复习之强连通分量以及缩点—Tarjan算法
  17. R pdf大小_全能格式转换工具分享,PDF 转 Word、视频图片格式转换等
  18. 计算机室内设计职业环境分析,室内设计职业规划书
  19. java解决跨域我呢提尼_野生狐狸被救以后,与狗狗成了好朋友,跨域种族的友情很不可思议...
  20. OSChina 周四乱弹 ——程序员用什么武器武装自己!

热门文章

  1. 直播报名|如何洞察消费者痛点?大数据分析为您支招!
  2. C语言顺序表:1、顺序表的存储、2、顺序表的实现.
  3. 随机信号的参数估计(AR)模型
  4. 十二、构建一个基本的组合导航系统
  5. 【以太网硬件TCP/IP协议栈】硬件协议栈W5500应用
  6. pascal编程语言介绍
  7. STM32CubeIDE HAL库操作IIC (二)案例篇(MPU9250)
  8. 【开发教程9】疯壳·人形街舞机器人-整机代码
  9. R语言可视化散点图、使用ggrepel包的geom_text_repel函数避免数据点之间的标签互相重叠(设置min.segment.length参数为Inf不添加标签线段)
  10. vt100 c语言控制,【转】C语言中控制printf的打印颜色实例及vt100的控制符文档