文档章节

Android Browser学习十二 UrlInputView

SuShine
 SuShine
发布于 2014/09/05 22:27
字数 1540
阅读 290
收藏 0

这段时间忙的要死, 但是还是不能忘掉自己的学习啊. 虽然读谷歌的代码确实有时候累觉不爱,但是现在却发现其实自己的不知不觉中进步, 现在基本上什么代码拿到手都不会心慌了.有时候还能把自己学习到的东西应用到项目中去, 这确实很美妙.


废话说到这里, 今天分享的是Browser的TitleBar模块, 也就是框计算模块,和chrome一样, android的浏览器的地址栏同样也是一个搜索框, 在UC和百度就应该叫做框计算了吧.其实看似很简单的需求,里面的内容还是很多的.

浏览器框计算的图片如下

读者可以一看就知道使用AutoCompleteTextView就可以实现, 确实是这样, android的chrome qq浏览器 都是类似的控件, 

UC使用的其实是一个edittext + listview 可以更好的扩展各种业务, 删除等操作了.

我们还是回来看browser的实现也就是UrlInputView.java

UML


public class UrlInputView extends AutoCompleteTextView
        implements OnEditorActionListener,
        CompletionListener, OnItemClickListener, TextWatcher


果然是继承了这个AutoCT

他的初始化过程:

 private void init(Context ctx) {
        mInputManager = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
        setOnEditorActionListener(this);
        //对于AutoCompleteTextView, 只要设置了他的Adapter 当用户输入某些字符的时候,他就会自己进行匹配了
        //缺点是可能不好自己定制一些东西
        mAdapter = new SuggestionsAdapter(ctx, this);
        setAdapter(mAdapter);
        setSelectAllOnFocus(true);
        onConfigurationChanged(ctx.getResources().getConfiguration());
        setThreshold(1);//输入一个字符就可以联想
        setOnItemClickListener(this);
        mNeedsUpdate = false;
        addTextChangedListener(this);

        mState = StateListener.STATE_NORMAL;
    }

这个UrlInputView有三种状态

static interface StateListener {
        static final int STATE_NORMAL = 0;
        static final int STATE_HIGHLIGHTED = 1;
        static final int STATE_EDITED = 2;

        public void onStateChanged(int state);
    }

在焦点发生变化, 触摸, 和输入状态发送变化的时候, 会更改UrlInputView的状态,

 protected void onFocusChanged(boolean focused, int direction, Rect prevRect) {
        super.onFocusChanged(focused, direction, prevRect);
        int state = -1;
        if (focused) {
            if (hasSelection()) {
                state = StateListener.STATE_HIGHLIGHTED;
            } else {
                state = StateListener.STATE_EDITED;
            }
        } else {
            // reset the selection state
            state = StateListener.STATE_NORMAL;
        }
        final int s = state;
        post(new Runnable() {
            public void run() {
                changeState(s);
            }
        });
    }

@Override
    public boolean onTouchEvent(MotionEvent evt) {
        boolean hasSelection = hasSelection();
        boolean res = super.onTouchEvent(evt);
        //
        //Return the masked action being performed, without pointer index information. Use getActionIndex() to return the index associated with pointer actions.
        // 翻译意思大概:返回经过掩码的action,没有触控点索引信息. 通过getActionIndex()来得到触控操作点的索引.
        if ((MotionEvent.ACTION_DOWN == evt.getActionMasked())
              && hasSelection) {
            postDelayed(new Runnable() {
                public void run() {
                    changeState(StateListener.STATE_EDITED);
                }}, POST_DELAY);
        }
        return res;
    }

  @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (StateListener.STATE_HIGHLIGHTED == mState) {
            changeState(StateListener.STATE_EDITED);
        }
    }

这个状态的变化会回调到Titlebar的onStateChanged函数 , Titlebar的各个图标随之会变化

UrlInputView是一个下拉列表, 所以自然有他的Adapter也就是 SuggestionsAdapter

其初始化

 public SuggestionsAdapter(Context ctx, CompletionListener listener) {
        mContext = ctx;
        mSettings = BrowserSettings.getInstance();
        mListener = listener;
        mLinesPortrait = mContext.getResources().
                getInteger(R.integer.max_suggest_lines_portrait);
        mLinesLandscape = mContext.getResources().
                getInteger(R.integer.max_suggest_lines_landscape);

        //添加过滤器, AutoCompleteTextView 会通过getFilter拿到
        //这个自定义的filter 这样
        //这样每当textview输入文字时候 就会先 mAdapter.getItem(position);
        //mFilter.convertResultToString(item), 
        //filter就会去拿相关数据了
        mFilter = new SuggestFilter();
        addSource(new CombinedCursor());
    }


这里的Filter 是根据输入的内容, 过滤出结果列表的功能, 这是给AutoCT使用的, 我们自定义了过滤的内容

/*
     * 联想过滤类 根据textview的输入请求数据
     * 
     * 过滤器通过过滤模式来约束数据,通常由实现了Filterable接口的子类来生成。
     *  过滤操作是通过调用 filter(CharSequence) 或者
     * filter(CharSequence, android.widget.Filter.FilterListener)这些异步方法来完成的。
     * 以上方法一旦被调用,过滤请求就会被递交到请求队列中等待处理,
     * 同时该操作会取消那些之前递交的但是还没有被处理的请求。
     */
    class SuggestFilter extends Filter {

    	/*这里是点一下把下面的text 填充到edittext中*/
        @Override
        public CharSequence convertResultToString(Object item) {
            if (item == null) {
                return "";
            }
            SuggestItem sitem = (SuggestItem) item;
            if (sitem.title != null) {
                return sitem.title;
            } else {
                return sitem.url;
            }
        }
        /* 异步发送联想过滤*/
        void startSuggestionsAsync(final CharSequence constraint) {
            if (!mIncognitoMode) {
                new SlowFilterTask().execute(constraint);
            }
        }
        /**
         * 是否出来空查询 默认是false
         */
        private boolean shouldProcessEmptyQuery() {
            final SearchEngine searchEngine = mSettings.getSearchEngine();
            return searchEngine.wantsEmptyQuery();
        }
        /*AutoCompleteTextview mFilter.filter 最后调用到子类的这个函数*/
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults res = new FilterResults();
            if (mVoiceResults == null) {
                if (TextUtils.isEmpty(constraint) && !shouldProcessEmptyQuery()) {
                    res.count = 0;
                    res.values = null;
                    return res;
                }
                startSuggestionsAsync(constraint);
                List<SuggestItem> filterResults = new ArrayList<SuggestItem>();
                if (constraint != null) {
                    for (CursorSource sc : mSources) {
                        sc.runQuery(constraint);
                    }
                    /*把mSources 中的数据 放到 filterResults中*/
                    mixResults(filterResults);
                }
                synchronized (mResultsLock) {
                    mFilterResults = filterResults;
                }
                SuggestionResults mixed = buildSuggestionResults();
                res.count = mixed.getLineCount();
                res.values = mixed;
            } else {
                res.count = mVoiceResults.size();
                res.values = mVoiceResults;
            }
            return res;
        }
        /*把mSources 中的数据 放到 results中*/
        void mixResults(List<SuggestItem> results) {
            int maxLines = getMaxLines();
            for (int i = 0; i < mSources.size(); i++) {
                CursorSource s = mSources.get(i);
                int n = Math.min(s.getCount(), maxLines);
                maxLines -= n;
                boolean more = false;
                for (int j = 0; j < n; j++) {
                	//取出一个item后 mCursor 下移一个 添加下一个item
                    results.add(s.getItem());
                    more = s.moveToNext();
                }
            }
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults fresults) {
            if (fresults.values instanceof SuggestionResults) {
                mMixedResults = (SuggestionResults) fresults.values;
                notifyDataSetChanged();//最后通知list更新各种数据
            }
        }
    }

这个Filter的调用来自AutoCompleteTextView : 的 TextWAtcher, 然后就开始进行对数据的过滤

 /**
     * This is used to watch for edits to the text view.  Note that we call
     * to methods on the auto complete text view class so that we can access
     * private vars without going through thunks.
     */
    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 doAfterTextChanged() { 
        if (mBlockCompletion) return;

        // if the list was open before the keystroke, but closed afterwards,
        // then something in the keystroke processing (an input filter perhaps)
        // called performCompletion() and we shouldn't do any more processing.
        if (DEBUG) Log.v(TAG, "after text changed: openBefore=" + mOpenBefore
                + " open=" + isPopupShowing());
        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) { //在构造器中拿到的Filter
                mPopupCanBeUpdated = true;
                performFiltering(getText(), mLastKeyCode); //至于AutoCT是继承的Edittext
            }
        } 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);
            }
        }
    }


其实AutoCT 使用的就是一个 ListPopupWindow 来展示下拉上拉的popupwindow

  public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mPopup = new ListPopupWindow(context, attrs,
                com.android.internal.R.attr.autoCompleteTextViewStyle);
        mPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);

综上, UrlInputView 是一个高度定制的AutoCT, 如果让我们去做可能用的是一个个控件去组合, 但是谷歌只用了一个AutoCT来实现, 可真的看出来Android的控件就是这群人写的. UrlInputView并且包括了联想词, 历史词等复杂的逻辑.

值得我们去学习借鉴.

UrlinputView 通过自定义的 SuggestionsAdapter, 在adapter中实现由两个Cursor组成的Filter从而实现了搜索联想词功能, 我们会在下一章做介绍

© 著作权归作者所有

SuShine
粉丝 128
博文 591
码字总数 158440
作品 0
朝阳
后端工程师
私信 提问
Android实战经验之图像处理及特效处理的集锦(总结版)

1 Android学习笔记进阶之在图片上涂鸦(能清屏) 2 Android学习笔记之详细讲解画圆角图片 3 Android学习笔记进阶20之得到图片的缩略图 4 Android学习笔记进阶19之给图片加边框 5 Android学习笔...

xiaosi
2012/03/12
40.1K
25
Android 进阶学习笔记整理

一.android系统架构图及各层介绍 1. 应用层:应用是用java语言编写的运行在虚拟机上的程序,比如通讯录,日历,电话,短信,浏览器等。 2. 应用框架层:这一层是编写Google发布的核心应用时所...

FunCode
2018/07/22
0
0
Android学习-列表视图ListView

一、简介: ListView,列表视图,直接继承了AbsListView,是一个以垂直方式在项目中显示View视图的列表。ListView的数据项,来自一个继承了ListAdapter接口的适配器。 二、新建一个包listvie...

YouChaoMin
2018/11/28
0
0
Android Browser学习二 BrowserActivity 的初始化 --其他重要模块

BrowserActivity 是浏览器的核心Activity了, 是浏览器的入口, 但是他里面并没有出来很多复杂的逻辑, 只是实现一些android 系统对activity的回调. 这些逻辑交给了Controller来处理, 就让我们一...

SuShine
2014/02/08
5.4K
0
unity跨平台sqlite使用教程

最近做的一个新项目,需要处理大量数据和动态图表展示。 并且结合跨平台使用的问题,考虑再三,计划使用Unity3D+SQLite进行开发。 因为跨平台的需求,先忽略UnityStore的收费SQLite插件。在G...

二哈卖豆腐
03/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
今天
2K
14
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
38
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
40
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
61
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
20
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部