AutoCompleteTextView下拉内容动态更新

news/2024/5/19 4:00:57 标签: Android, AutoCompleteTextView, 反射

1.绪论

一般来说,使用AutoCompleteTextView这个控件是给用户输入时提供选择提示的,而这个提示的列表是预先设置进去的,后面不在改变。但在现实场景中,这并不能满足需求,大部分需求是这个提示列表需根据输入的关键字通过网络请求查询,然后将查询的结果展示出来,供用户选择。也就是说提示列表是动态变化的。这样的需求使用AutoCompleteTextView控件怎么实现呢?

AutoCompleteTextView_5">2.AutoCompleteTextView源码分析

要实现上面的需求就必须要了解AutoCompleteTextView是怎么工作的,它的实现逻辑如下:

1.AutoCompleteTextView 继承 EditText
2.需要ListAdapter并且要继承Filter类

public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
        if (mObserver == null) {
            mObserver = new PopupDataSetObserver(this);
        } else if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mObserver);
        }
        mAdapter = adapter;
        if (mAdapter != null) {
            //noinspection unchecked
            mFilter = ((Filterable) mAdapter).getFilter();
            adapter.registerDataSetObserver(mObserver);
        } else {
            mFilter = null;
        }
        mPopup.setAdapter(mAdapter);
    }

3.添加监听addTextChangedListener

addTextChangedListener(new MyWatcher());
//下面MyWatcher类的实现
private class MyWatcher implements TextWatcher {
        public void afterTextChanged(Editable s) {
            doAfterTextChanged();
        }
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            doBeforeTextChanged();
        }
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    }
    //此方法是记录下拉框的显示状态
    void doBeforeTextChanged() {
        if (mBlockCompletion) return;
        // when text is changed, inserted or deleted, we attempt to show the drop down
        mOpenBefore = isPopupShowing();
    }
    //此方法是根据输入的内容找到匹配项,通过下拉框展示出来
    void doAfterTextChanged() {
        if (mBlockCompletion) return;
        if (mOpenBefore && !isPopupShowing()) {
            return;
        }
        // the drop down is shown only when a minimum number of characters was typed in the text view
        if (enoughToFilter()) {
            if (mFilter != null) {
                mPopupCanBeUpdated = true;
                performFiltering(getText(), mLastKeyCode);
            }
        } else {
            // drop down is automatically dismissed when enough characters are deleted from the text view
            if (!mPopup.isDropDownAlwaysVisible()) {
                dismissDropDown();
            }
            if (mFilter != null) {
                mFilter.filter(null);
            }
        }
    }

4.通过Filter类来找到匹配项,并通过popwindow展示出来

3.实现思路

从源码来看,当EditText内容改变时,就会立马从提示列表中找出匹配项,并展示出来;根本来不及去网络请求,然后将请求结果更新提示列表,再进行筛选。
或许此时,会有这样的一个想法,将网络请求更新提示列表这个动作放在Filter之前
执行不就好了。这个想法不可行,因为AutoCompleteTextView执行流程是不可控的。
既然流程不可控,那是否可以重新执行一遍此流程呢?当我们请求网络后,将结果更新提示列表,然后让系统重新执行doAfterTextChanged这个方法不就可以了么?很激动!!!

4.解决方案

想法很关键,代码实现不难,所以上面重点将源码分析和思路说了一下,当你认真看懂了源码,看懂系统是怎么实现此功能的,你才能在系统的基础上新增功能来实现自己的需求。下面是实现步骤:

1.监听EditText的addTextChangedListener
2.根据输入的内容请求网络,获取提示列表
3.更新列表,调用AutoCompleteTextView类的doAfterTextChanged方法,筛选并弹框

关键代码如下:

//添加兼听
       autoTVCheck.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable editable) {
                long time = DateUtil.getCurrentTimeInMills();
                //输入的字符间隔时间 小于700毫秒 移除以前的handler 延时600毫秒执行
                if (autoTVCheck.getTag() != null && time - (Long) autoTVCheck.getTag() < 700) {
                    searchHandler.removeMessages(1);
                }
                searchHandler.sendEmptyMessageDelayed(1, 600);
                autoTVCheck.setTag(time);
            }
        });
        //延时搜索的handler
        private Handler searchHandler = new Handler(Looper.getMainLooper()) {
        public void handleMessage(Message msg) {
            dealSearchHint();
        }
    };
    /**
     * 根据用户输入的字符去调用接口查询符合的订单或桌台名
     */
    private void dealSearchHint(){
        String searchContent = autoTVCheck.getText().toString();
        if(searchContent.isEmpty()){
            return;
        }
        //接口-模糊查询符合的订单或桌台名
        mProcess.getSearchDropList(searchContent,new ResultCallback<GetOrderFromCenterRespone>(){
                @Override
                public void onSuccess(GetOrderFromCenterRespone data) {
                    if(data != null && !ListUtil.isEmpty(data.orderList2)){
                    	//更新提示列表
                        searchAdapter.setOrderListModels(data.orderList2);
                        refreshDropList();
                    }
                }
        });
    }
    //AutoCompleteTextView的doBeforeTextChanged方法
    Method doBeforeTextChanged;
    //AutoCompleteTextView的doAfterTextChanged方法
    Method doAfterTextChanged;

    /**
     * 下拉提示框数据获取到后刷新此框
     * 通过反射调用AutoCompleteTextView的doBeforeTextChanged和doAfterTextChanged方法来实现刷新下拉提示框
     */
    private void refreshDropList(){
        try{
            if(doAfterTextChanged == null){
                Class autoCompleteTextView = Class.forName("android.widget.AutoCompleteTextView");
                doBeforeTextChanged = autoCompleteTextView.getDeclaredMethod("doBeforeTextChanged");
                doBeforeTextChanged.setAccessible(true);
                doAfterTextChanged = autoCompleteTextView.getDeclaredMethod("doAfterTextChanged");
                doAfterTextChanged.setAccessible(true);
            }
            autoTVCheck.showDropDown();
            doBeforeTextChanged.invoke(autoTVCheck);
            doAfterTextChanged.invoke(autoTVCheck);
        }catch (Exception e){}
    }

到此呢,AutoCompleteTextView下拉内容动态更新功能就写完了,从上一篇到现在编写这一篇,中间隔了将近一年,也是换工作以来,写的第一篇。可以看出来 换个环境真的很影响生活,影响工作,因为你要去适应和熟悉新的工作环境,要熟悉新工作的代码和以往的业务。当然,这些都是值得的!!

还是那句老话,如果屏前的你有一定的收获的话,那么请您给笔者点个赞或者留个言吧~

屏前的你,加油!!!


http://www.niftyadmin.cn/n/995556.html

相关文章

JS导出Excel表格

为什么80%的码农都做不了架构师&#xff1f;>>> <div > <button type"button" id"five">导出Excel方法五</button> </div> <div id"myDiv"> <table id"tableExcel" width"1…

2016年,安防大佬们活得都还好吗?

1、海康威视&#xff08;002415&#xff09;2016年度总营收320亿&#xff0c;净利润74亿 杭州海康威视数字技术股份有限公司2016年度&#xff0c;公司实现营业总收入32&#xff0c;017&#xff0c;423&#xff0c;704&#xff0e;00元&#xff0c;比上年同期增长26&#xff0e;…

QQ号码被要求输验证码的解决方法

Q&#xff1a;什么是验证码&#xff1f; A&#xff1a;QQ登录采用的是图片验证码&#xff0c;它是包含无规律字符信息的图片。普通用户用肉眼就可以辨认其中的字符信息&#xff0c;但通过恶意软件自动登录的行为(用意不善的用户用行为不合法的软件登录系统或网站&#xff0c;而…

HelloFresh迁移至新的API网关,实现微服务架构

HelloFresh最近以零停机的方式将应用迁移到了一个新的API网关&#xff0c;其技术总监talo Lelis de Vietro在一篇文章中分享了他们所面临的挑战以及迁移的过程。 在这次迁移之前&#xff0c;HelloFresh已有的API是单体架构的。为了迁移至微服务架构并让微服务的创建更加简单&am…

基于高斯模型的彩色图像反向投影

一&#xff1a;介绍 图像反向投影的最终目的是获取ROI然后实现对ROI区域的标注、识别、测量等图像处理与分析&#xff0c;是计算机视觉与人工智能的常见方法之一。图像反向投影通常是彩色图像投影效果会比灰度图像效果要好&#xff0c;原因在于彩色图像带有更多对象细节信息&am…

[代码保留]ORA-01033: ORACLE initialization or shutdown in progress

错误编码&#xff1a;ORA-01033: ORACLE initialization or shutdown in progress 故障描述&#xff1a;因为移动了数据库文件&#xff08;[NAME].DMP&#xff09;/日志文件等文件&#xff0c;导致数据库连接出现ORA-01033错误。 故障分析&#xff1a;[观点来自网络本人并不保证…

大数据助推油气生产物联网升级

笔者3月底获悉&#xff0c;国家工信部“互联网能源”工业转型升级重大专项日前在新疆油田公司召开项目启动会。这是推进“两化”融合与“互联网能源”的一次重要实践&#xff0c;也是深化智能新疆油田建设的一次重要探索。 由新疆油田公司和红有软件申报的《基于IPv6TD-LTE大数…

让背景如此暗淡(一种弹出提示信息时页面背景色调改变的方法)

http://bbs.blueidea.com/thread-2676327-1-1.html<head><meta http-equiv"Content-Type"content"text/html; charsetgb2312"/><title>提示信息框</title><style type"text/css">a{}{ color:#000; font-size:12px…