webview應該是開發人員最常接觸的控件了,加載一個頁面的時候,webview.loadUrl(url)就完事了,我遇到這麼玩webview的一般都是在界面顯示一些應用說明或是版本信息的時候比較常見,但是,這樣根本發揮不了webview的潛能,接下來,我會出幾篇比較好玩的文章,帶大家爽一爽,今天這一篇或許對有些基礎的人並不感冒,但可以看看後面的文章,會給你們帶來驚喜的。
初探我會跟着官網的API來分析,讓大家瞭解瞭解這些是拿來幹什麼的。
Basic usage(基本用法)
對於打開一個url我們可能會有兩種方法,一個是通過外部瀏覽器去打開,另一種則是通過自己的應用的webview去打開,官網也給出了兩種用法。
通過外部瀏覽器打開
Uri uri = Uri.parse("http://www.example.com");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
通過內部webview打開
WebView webview = new WebView(this);
setContentView(webview);
webview.loadUrl("http://slashdot.org/");
String summary = "<html><body>You scored <b>192</b> points.</body></html>";
webview.loadData(summary, "text/html", "utf-8");
customization points(定製)
對於上面的webview的基本用法我們已經知道了,接下來,我們看一些定製webview需要了解哪些東西。
(一)WebChromeClient
官網解釋:This class is called when something that might impact a browser UI happens,for instance, progress updates and JavaScript alerts are sent here
大概意思是,這個類能做一些對界面的渲染效果,比如加載webview的進度更新或是js的對話框
(二)WebViewClient
官網解釋:It will be called when things happen that impact the rendering of the content, eg, errors or form submissions. You can also intercept URL loading here
大概意思就是,當webview加載的時候,這個類有很多的方法會被回調,比如webview的開始加載,加載錯誤,加載完成等回調處理,關鍵看後面這一句,你也可以攔截url的加載,這句話很關鍵,後面會用上,這個攔截需要依賴這個類的一個方法—shouldOverrideUrlLoading()
(三)WebSettings
官網解釋:Modifying the WebSettings, such as enabling JavaScript with setJavaScriptEnabled()
這個類主要是對於webview進行一些設置,比如是否允許加載js等,這個也是我們比較常用的。
(四)addJavascriptInterface(Object, String)
官網解釋:Injecting Java objects into the WebView using the addJavascriptInterface(Object, String) method. This method allows you to inject Java objects into a page’s JavaScript context, so that they can be accessed by JavaScript in the page.
這個類是重中之重,他發揮了webview的特性,他就好比是網頁與原生溝通的一個橋樑,網頁中的js能調用android內的控件,android能通過js去處理網頁,就像官網的解釋那樣,這個方法允許你注入java對象實現js的上下文
使用
上面介紹的差不多了,接下來,我們要學會如何去使用他,我們先從上面的介紹一步一步的開始
WebChromeClient的使用
我們見過很多瀏覽器的效果,在加載網頁的時候,頭部有個進度條一直跟着顯示加載進度,該實現方式就是通過如下的代碼實現的,我們可以在webview的頭部添加一個progressbar控件的橫向樣式,設置max最大值爲100,因爲WebChromeClient的onProgressChanged方法回調的progress加載完成的時候也是100。
webview.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
progressBar.setProgress(progress);
Log.i(TAG,"--->"+progress);
}
});
如圖
WebViewClient的使用
該方法就好比是webview的一個生命週期,有網頁加載開始回調,加載失敗回調,加載成功回調。然而,僅僅就這三個方法,卻可以幫我們完成很多很多的事情。
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.i(TAG, "-------->網頁加載開始");
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { {
Log.i(TAG, "-------->網頁加載錯誤");
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.i(TAG, "------>網頁加載完成");
}
});
根據方法名字我們就知道其中的意思了,我相信,在這樣的一個週期當中,很多開發者都有這樣的需求。
網頁加載失敗或是沒有網絡的時候,我們爲了不想讓用戶看到“找不到網頁”這樣的頁面,我們習慣自己定製加載失敗的頁面去告知用戶,然後點擊重新加載,繼續加載。這樣符合用戶的體驗,這時候,這個週期就非常的符合要求了。
注意:我們要知道一點的就是,無論webview加載成功還是加載失敗,最後一個觸發的都是加載完成的回調,所以,我們在處理加載失敗頁面的時候,需要在onReceivedError設置一個標誌位,告訴onPageFinished剛剛加載的是一個錯誤的頁面。
用法:我們可以在根佈局RelativeLayout下創建兩個佈局,設置加載失敗頁面爲gone,設置webview也爲gone,progressbar設置爲visible,我們在loadUrl加載頁面的時候,我們在onPageStarted去初始化狀態,比如,設置當前是否是錯誤頁面flag=false,設置webview爲gone,設置錯誤頁面爲gone,然後在onReceivedError裏面只需要設置當前頁面是錯誤頁面flag=true,最後,我們在onPageFinished加載完成的時候去做個判斷,如果flag爲false表示加載成功,這時候我們設置webview爲visible,如果flag爲ture表示加載錯誤,我們就設置錯誤頁面爲visible,webview爲gone,最後設置progressBar爲gone,然後給錯誤頁面設置一個點擊事件,點擊該按鈕就是重新加載,這樣,一個體驗不錯的小功能就出來了。
圖:該處我把上面的progressbar也設置了一下,在加載完成的時候設置爲gone,在開始加載的時候visible。我也把加載過程的生命週期也Toast出來了,方便查看
對了,還有一個方法沒有說
public boolean shouldOverrideUrlLoading(WebView view, String url)
官網解釋:return true means the host application handles the url, while return false means the current WebView handles the url
這個方法還是很有意思,他可以做到對頁面的url攔截,現在方法內什麼都不寫,如果return返回了true,就交給手機的應用去處理這個url,親測的時候,當返回true的時候,頁面的鏈接點擊是沒有效果的,如果返回false,url直接在webview進行加載,
但是,我又遇到一個好玩的。我們在該方法內使用 view.loadUrl(url);繼續加載這個鏈接,這時候,無論是設置true還是false,頁面都會在webview進行加載,所以,感覺這個方法有點雞肋啊,怪不得這個方法現在加上了刪除線,不推薦使用了。
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
WebSettings
該類就是輔助webview的一些設置,比如有
WebSettings seting = webView.getSettings();
//設置加載網頁的js可用,這個設置對後面要講到的js與android交互的時候會使用到
seting.setJavaScriptEnabled(true);
// 設置允許JS彈窗
seting.setJavaScriptCanOpenWindowsAutomatically(true);
// 防止中文亂碼
seting.setDefaultTextEncodingName("UTF-8");
// 設置可以支持縮放
seting.setSupportZoom(true);
// 設置緩存是否可用
seting.setAppCacheEnabled(true);
//設置webview的緩存
seting.setCacheMode(WebSettings.LOAD_NO_CACHE);
// 設置出現縮放工具
seting.setBuiltInZoomControls(false);
// 自適應屏幕seting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
addJavascriptInterface
該方法纔是webview最好玩的的地方,如下使用
seting.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JSObject(), “jsAndroid”);
該方法首先得設置能加載js才能使用,addJavascriptInterface有兩個方法,一個是對象,這個對象裏面設置了好多以@JavascriptInterface爲註解的方法,目的是爲js提供調用原生的入口,第二個參數就好比是new一個對象的變量,就相當於JSObject js=new JSObject(),第二個參數就好比是那個js對象 。我們來看看官網給我們的例子
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
//添加網頁內容
webView.loadData("", "text/html", null);
//添加js代碼
webView.loadUrl("javascript:alert(injectedObject.toString())");
上面的demo主要目的是通過js拿android的數據。
如圖:
爲了更好的演示js與webview的交互,我還是寫個網頁出來。
Html頁面代碼
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function javaToJs() {
document.getElementById("main").innerHTML = "<br\>java調用了js的無參函數";
}
function javaToJsValue(arg) {
document.getElementById("main").innerHTML = ("<br\>java調用了js的有參數函數--->" + arg);
}
</script>
</head>
<body>
<h1 id="main">webview與js交互</h1>
<input type="button" value="調用java代碼 無參函數" onclick="window.jsAndroid.setValue()">
<input type="button" value="調用java代碼 帶參函數" onclick="window.jsAndroid.setValue('我是被js帶過來的')">
</body>
</html>
java代碼
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWeb();
initSetting();
webView.addJavascriptInterface(new JSObject(), "jsAndroid");
webView.loadUrl("http://192.168.7.248/web.html");
}
private void initWeb() {
webView = (WebView) findViewById(R.id.webview);
}
private void initSetting() {
seting = webView.getSettings();
seting.setJavaScriptEnabled(true);
// 設置允許JS彈窗
seting.setJavaScriptCanOpenWindowsAutomatically(true);
//防止中文亂碼
seting.setDefaultTextEncodingName("UTF-8");
//設置webview的緩存
seting.setCacheMode(WebSettings.LOAD_NO_CACHE);
}
//button無參的點擊事件
public void jstoAndroid(View v){
webView.loadUrl("javascript:javaToJs()");
}
//button帶參的點擊事件
public void jstoAndroidValue(View v){
webView.loadUrl("javascript:javaToJsValue('hello')");
}
class JSObject {
@JavascriptInterface
public void setValue(){
Toast.makeText(MainActivity.this, "js調用了java代碼 無參函數", Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public void setValue(String str){
Toast.makeText(MainActivity.this, "js調用了java代碼 有參函數,c傳遞的數據是---->"+str, Toast.LENGTH_SHORT).show();
}
}
結果顯示如圖:
好了,講了差不多了,此處就不提供源碼了,這篇主要提供思路,下一篇纔是精彩。