WebView實現頁內文字查詢功能

大頭呆發表於2018-01-26

最近閒來無事一直在學習WebView的知識,最近幾篇部落格也都和這個有關。看了好久WebView的Api,終於找到了一個拿的出手給大家分享(水)的功能了。看標題,就知道是搜尋匹配當前網頁內的關鍵詞的功能啦,慣例先放下成品圖(UI參照了桌面版的Chrome):

WebView實現頁內文字查詢功能

效果和桌面版Chrome的頁內搜尋也是差不多的。下面就介紹下相關相關Api和具體實現流程吧。

Api

void findAllAsync(String find)

找到網頁內所有關鍵詞,看方法名字知道是非同步查詢的。所有找到的匹配項都會用顏色標記(上圖是黃色)。

void findNext(boolean forward)

切換所找到關鍵詞列表的匹配項。forward是切換方向,true切換到下一個,false切換到前一個。當前選中的匹配項會用另外一個顏色標記(橙色)。注意切換的操作是迴圈的,比如已經在最後一項了,再往前切換就會回到第一個匹配項。

void setFindListener(FindListener listener)

設定介面監聽器,回撥查詢的結果,其中FindListener就一個方法:

 public void onFindResultReceived(int activeMatchOrdinal//當前匹配列表項的序號(從0開始)
 ,int numberOfMatches//所有匹配關鍵詞的個數
 ,boolean isDoneCounting);//有沒有查詢完成
複製程式碼

void clearMatches()

清除所有找到的關鍵詞的顏色標記。用來做復原操作。

以下是一些過時(廢棄)的方法:

boolean showFindDialog(String text, boolean showIme)

找到關鍵詞,並顯示彈框。原來WebView有內建的查詢文字的彈框,可惜在所有android版本的系統上這個方法都不一定有用。

int findAll(String find)

findAllAsync的同步版本,返回的是查詢的結果的個數。猜測如果網頁內文字太多,同步查詢可能引起UI執行緒阻塞,所以系統建議我們採用非同步的查詢方式。

好了主要方法就是以上這些,下面講下具體的實現流程。

實現流程

整個查詢的流程(包括顯示細節)都仿照了了Chrome的查詢方式。

彈框最初我選擇了DialogFrgment,但是dialog會阻塞Webview獲取焦點。因為我們預期的結果是查詢到所有匹配項後仍能夠自己滑動WebView檢視。所有隻能直接寫在WebView的佈局裡面。為了優化佈局載入速度,可以採用如下引用方式:

<ViewStub 
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/search_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content" 
/>
複製程式碼

這樣就能實現佈局的延遲載入。當然最好的方法還是選擇dialog或者poupwindow。可惜沒有解決焦點的問題。 註冊查詢回撥的介面,注意下標索引是從0開始的,所以要加1:

 mWebView.setFindListener(new IX5WebViewBase.FindListener() {
            @Override
            public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
                                             boolean isDoneCounting) {
                if (isDoneCounting) {
                    if (numberOfMatches != 0) {
                        searchInfo.setText(String.format("%d/%d", (activeMatchOrdinal + 1), numberOfMatches));
                    } else {
                        searchInfo.setText("0/0");
                    }
                }
            }
        });
複製程式碼

通過監聽輸入框的內容變化進行動態的文字查詢。

mEditText.addTextChangedListener(new SimpleTextWatcher() {
            @Override
            public void afterTextChanged(Editable s) {
                if (TextUtils.isEmpty(mEditText.getText().toString())) {
                    searchInfo.setVisibility(View.INVISIBLE);
                } else {
                    searchInfo.setVisibility(View.VISIBLE);
                }
                String content = s.toString();
                if (!TextUtils.isEmpty(content)) {
                    mWebView.findAllAsync(content);
                }
            }
        });

複製程式碼

在彈框查詢框同時要彈出輸入框。並且需要判斷有沒有存在內容,有的話直接查詢,但是這只是為了顯示找到匹配項的個數,所以清除顏色標記。

String content=mEditText.getText().toString();
        if (TextUtils.isEmpty(content)) {
            searchInfo.setVisibility(View.INVISIBLE);
        } else {
            mWebView.findAllAsync(content);
            mWebView.clearMatches();
            searchInfo.setVisibility(View.VISIBLE);
        }
        KeyboardUtils.showSoftInput(getContext(), mEditText);
複製程式碼

在隱藏查詢框的時候隱藏輸入框和清楚匹配項的顏色標記:

searchLayout.setVisibility(View.GONE);
KeyboardUtils.hideSoftInput(getActivity(), mEditText);
mWebView.clearMatches();
複製程式碼

查詢框的進入消失動畫可以用Transition實現 TransitionManager.beginDelayedTransition(mViewGroup, new Slide(Gravity.TOP));

以上差不多就是所有的實現要點了。

小結

貼下本文程式碼的地址

Github

關於WebView之前已經寫過幾篇部落格了。對這方面感興趣的同學可以看下我的其他相關部落格(Github地址同上):

擼一款全手勢操作瀏覽器

WebView實現長按儲存圖片 長按識別二維碼

相關文章