最近閑來無事一直在學(xué)習(xí)WebView的知識(shí),最近幾篇博客也都和這個(gè)有關(guān)。看了好久WebView的Api,終于找到了一個(gè)拿的出手給大家分享(水)的功能了。看標(biāo)題,就知道是搜索匹配當(dāng)前網(wǎng)頁內(nèi)的關(guān)鍵詞的功能啦,慣例先放下成品圖(UI參照了桌面版的Chrome):
效果和桌面版Chrome的頁內(nèi)搜索也是差不多的。下面就介紹下相關(guān)相關(guān)Api和具體實(shí)現(xiàn)流程吧。
Api
void findAllAsync(String find)
找到網(wǎng)頁內(nèi)所有關(guān)鍵詞,看方法名字知道是異步查找的。所有找到的匹配項(xiàng)都會(huì)用顏色標(biāo)記(上圖是黃色)。
void findNext(boolean forward)
切換所找到關(guān)鍵詞列表的匹配項(xiàng)。forward是切換方向,true切換到下一個(gè),false切換到前一個(gè)。當(dāng)前選中的匹配項(xiàng)會(huì)用另外一個(gè)顏色標(biāo)記(橙色)。注意切換的操作是循環(huán)的,比如已經(jīng)在最后一項(xiàng)了,再往前切換就會(huì)回到第一個(gè)匹配項(xiàng)。
void setFindListener(FindListener listener)
設(shè)置接口監(jiān)聽器,回調(diào)查找的結(jié)果,其中FindListener
就一個(gè)方法:
public void onFindResultReceived(int activeMatchOrdinal//當(dāng)前匹配列表項(xiàng)的序號(hào)(從0開始)
,int numberOfMatches//所有匹配關(guān)鍵詞的個(gè)數(shù)
,boolean isDoneCounting);//有沒有查找完成
void clearMatches()
清除所有找到的關(guān)鍵詞的顏色標(biāo)記。用來做復(fù)原操作。
以下是一些過時(shí)(廢棄)的方法:
boolean showFindDialog(String text, boolean showIme)
找到關(guān)鍵詞,并顯示彈框。原來WebView有內(nèi)置的查找文字的彈框,可惜在所有android版本的系統(tǒng)上這個(gè)方法都不一定有用。
int findAll(String find)
findAllAsync的同步版本,返回的是查找的結(jié)果的個(gè)數(shù)。猜測(cè)如果網(wǎng)頁內(nèi)文字太多,同步查找可能引起UI線程阻塞,所以系統(tǒng)建議我們采用異步的查找方式。
好了主要方法就是以上這些,下面講下具體的實(shí)現(xiàn)流程。
實(shí)現(xiàn)流程
整個(gè)查找的流程(包括顯示細(xì)節(jié))都仿照了了Chrome的查找方式。
彈框最初我選擇了DialogFrgment,但是dialog會(huì)阻塞Webview獲取焦點(diǎn)。因?yàn)槲覀冾A(yù)期的結(jié)果是查找到所有匹配項(xiàng)后仍能夠自己滑動(dòng)WebView
查看。所有只能直接寫在WebView的布局里面。為了優(yōu)化布局加載速度,可以采用如下引用方式:
<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"
/>
這樣就能實(shí)現(xiàn)布局的延遲加載。當(dāng)然最好的方法還是選擇dialog或者poupwindow。可惜沒有解決焦點(diǎn)的問題。
注冊(cè)查找回調(diào)的接口,注意下標(biāo)索引是從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");
}
}
}
});
通過監(jiān)聽輸入框的內(nèi)容變化進(jìn)行動(dòng)態(tài)的文字查找。
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);
}
}
});
在彈框查找框同時(shí)要彈出輸入框。并且需要判斷有沒有存在內(nèi)容,有的話直接查找,但是這只是為了顯示找到匹配項(xiàng)的個(gè)數(shù),所以清除顏色標(biāo)記。
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);
在隱藏查找框的時(shí)候隱藏輸入框和清楚匹配項(xiàng)的顏色標(biāo)記:
searchLayout.setVisibility(View.GONE);
KeyboardUtils.hideSoftInput(getActivity(), mEditText);
mWebView.clearMatches();
查找框的進(jìn)入消失動(dòng)畫可以用Transition
實(shí)現(xiàn)
TransitionManager.beginDelayedTransition(mViewGroup, new Slide(Gravity.TOP));
以上差不多就是所有的實(shí)現(xiàn)要點(diǎn)了。
小結(jié)
貼下本文代碼的地址
關(guān)于WebView之前已經(jīng)寫過幾篇博客了。對(duì)這方面感興趣的同學(xué)可以看下我的其他相關(guān)博客(Github地址同上):