WebView(網(wǎng)頁(yè)視圖)基本用法
本節(jié)引言
本節(jié)給大家?guī)?lái)的是Android中的一個(gè)用于顯示網(wǎng)頁(yè)的控件:WebView(網(wǎng)頁(yè)視圖)。
現(xiàn)在Android應(yīng)用 層開(kāi)發(fā)的方向有兩種:客戶端開(kāi)發(fā)和HTML5移動(dòng)端開(kāi)發(fā)!
所謂的HTML5端就是:HTML5 + CSS + JS來(lái)構(gòu)建 一個(gè)網(wǎng)頁(yè)版的應(yīng)用,而這中間的媒介就是這個(gè)WebView,而Web和網(wǎng)頁(yè)端可以通過(guò)JS來(lái)進(jìn)行交互,比如, 網(wǎng)頁(yè)讀取手機(jī)聯(lián)系人,調(diào)用手機(jī)相關(guān)的API等!
而且相比起普通的客戶端開(kāi)發(fā),HTML5移動(dòng)端有個(gè)優(yōu)勢(shì): 可以用百分比來(lái)布局,而且如果HTML5端有什么大改,我們不用像客戶端那樣去重新下一個(gè)APP,然后 覆蓋安裝,我們只需修改下網(wǎng)頁(yè)即可!而客戶端...慘不忍睹,當(dāng)然HTML5也有個(gè)缺點(diǎn),就是性能的問(wèn)題, 數(shù)據(jù)積累,耗電問(wèn)題,還有閃屏等等...
另外,針對(duì)這種跨平臺(tái)我們可以使用其他的第三方快速開(kāi)發(fā) 框架,比如PhoneGap,對(duì)了,還有現(xiàn)在網(wǎng)絡(luò)上很多一鍵生成APP類的網(wǎng)站,用戶通過(guò)拖拉,設(shè)置圖片 之類的簡(jiǎn)單操作就可以生成一個(gè)應(yīng)用,大部分都是用的HTML5來(lái)完成的!有模板,直接套,你懂的~ 好的,話不多說(shuō),開(kāi)始本節(jié)內(nèi)容!
1.什么是WebView?
答:Android內(nèi)置webkit內(nèi)核的高性能瀏覽器,而WebView則是在這個(gè)基礎(chǔ)上進(jìn)行封裝后的一個(gè) 控件,WebView直譯網(wǎng)頁(yè)視圖,我們可以簡(jiǎn)單的看作一個(gè)可以嵌套到界面上的一個(gè)瀏覽器控件!
2.相關(guān)方法
先上官方文檔:WebView并不打算一個(gè)個(gè)地去講屬性,用到哪個(gè)寫哪個(gè),其他的自行查閱文檔! 除了直接WebView外我們還可以添加你自己的行為,可以自行定制下述類:
WebChromeClient:輔助WebView處理Javascript的對(duì)話框、網(wǎng)站圖標(biāo)、網(wǎng)站title、加載進(jìn)度等! 比如下面這些:
方法 | 作用 |
---|---|
onJsAlert(WebView view,String url,String message,JsResult result) | 處理Js中的Alert對(duì)話框 |
onJsConfirm(WebView view,String url,String message,JsResult result) | 處理Js中的Confirm對(duì)話框 |
onJsPrompt(WebView view,String url,String message,String defaultValue,JsPromptResult result) | 處理Js中的Prompt對(duì)話框 |
onProgressChanged(WebView view,int newProgress) | 當(dāng)加載進(jìn)度條發(fā)生改變時(shí)調(diào)用 |
onReceivedIcon(WebView view, Bitmap icon) | 獲得網(wǎng)頁(yè)的icon |
onReceivedTitle(WebView view, String title) | 獲得網(wǎng)頁(yè)的標(biāo)題 |
WebViewClient:輔助WebView處理各種通知與請(qǐng)求事件! 比如下面這些方法:
方法 | 作用 |
---|---|
onPageStared(WebView view,String url) | 通知主程序網(wǎng)頁(yè)開(kāi)始加載 |
onPageFinished(WebView view,String url,Bitmap favicon) | 通知主程序,網(wǎng)頁(yè)加載完畢 |
doUpdateVisitedHistory(WebView view,String url,boolean isReload) | 更新歷史記錄 |
onLoadResource(WebView view,String url) | 通知主程序WebView即將加載指定url的資源 |
onScaleChanged(WebView view,float oldScale,float newScale) | ViewView的縮放發(fā)生改變時(shí)調(diào)用 |
shouldOverrideKeyEvent(WebView view,KeyEvent event) | 控制webView是否處理按鍵時(shí)間,如果返回true,則WebView不處理,返回false則處理 |
shouldOverrideUrlLoading(WebView view,String url) | 控制對(duì)新加載的Url的處理,返回true,說(shuō)明主程序處理WebView不做處理,返回false意味著WebView會(huì)對(duì)其進(jìn)行處理 |
onReceivedError(WebView view,int errorCode,String description,String failingUrl) | 遇到不可恢復(fù)的錯(cuò)誤信息時(shí)調(diào)用 |
WebSettings:WebView相關(guān)配置的設(shè)置,比如setJavaScriptEnabled()設(shè)置是否允許JS腳本執(zhí)行 部分方法如下:
方法 | 作用 |
---|---|
getSettings() | 返回一個(gè)WebSettings對(duì)象,用來(lái)控制WebView的屬性設(shè)置 |
loadUrl(String url) | 加載指定的Url |
loadData(String data,String mimeType,String encoding) | 加載指定的Data到WebView中.使用"data:"作為標(biāo)記頭,該方法不能加載網(wǎng)絡(luò)數(shù)據(jù).其中mimeType為數(shù)據(jù)類型如:textml,image/jpeg. encoding為字符的編碼方式 |
loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) | 比上面的loadData更加強(qiáng)大 |
setWebViewClient(WebViewClient client) | 為WebView指定一個(gè)WebViewClient對(duì)象.WebViewClient可以輔助WebView處理各種通知,請(qǐng)求等事件。 |
setWebChromeClient(WebChromeClient client) | 為WebView指定一個(gè)WebChromeClient對(duì)象,WebChromeClient專門用來(lái)輔助WebView處理js的對(duì)話框,網(wǎng)站title,網(wǎng)站圖標(biāo),加載進(jìn)度條等 |
這里重要區(qū)分三個(gè)load方法的區(qū)別:
loadUrl():直接顯示網(wǎng)頁(yè)內(nèi)容(單獨(dú)顯示網(wǎng)絡(luò)圖片),一般不會(huì)出現(xiàn)亂碼。loadData(data, "text/html", "UTF-8"):用來(lái)加載URI格式的數(shù)據(jù),不能通過(guò)網(wǎng)絡(luò)來(lái)加載內(nèi)容, 不能加載圖片,而且經(jīng)常會(huì)遇到亂碼的問(wèn)題,我們知道String類型的數(shù)據(jù)主要是Unicode編碼的, 而WebView一般為了節(jié)省資源使用的是UTF-8編碼,盡管我們按上面寫了,但是還需要為webView設(shè)置: webview.getSettings().setDefaultTextEncodingName("UTF -8");loadDataWithBaseURL(baseUrl, string, "text/html", "utf-8", null):loadData類的一個(gè) 增強(qiáng)類,可以加載圖片,baseUrl為你存儲(chǔ)的圖片路徑,而且只需在這里設(shè)置utf-8就可以解決亂碼 問(wèn)題了!
這里只是列舉了部分屬性而已,其他的還需自行查閱官方文檔:
3.一些常見(jiàn)需求講解
需求1:根據(jù)URL加載網(wǎng)頁(yè)
1)直接在Activity上加載一個(gè)WebView
運(yùn)行效果圖:
實(shí)現(xiàn)代碼:
public class MainActivity extends AppCompatActivity { private WebView webView; private long exitTime = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = new WebView(this); webView.setWebViewClient(new WebViewClient() { //設(shè)置在webView點(diǎn)擊打開(kāi)的新網(wǎng)頁(yè)在當(dāng)前界面顯示,而不跳轉(zhuǎn)到新的瀏覽器中 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); webView.getSettings().setJavaScriptEnabled(true); //設(shè)置WebView屬性,運(yùn)行執(zhí)行js腳本 webView.loadUrl("http://www.baidu.com/"); //調(diào)用loadView方法為WebView加入鏈接 setContentView(webView); //調(diào)用Activity提供的setContentView將webView顯示出來(lái) } //我們需要重寫回退按鈕的時(shí)間,當(dāng)用戶點(diǎn)擊回退按鈕: //1.webView.canGoBack()判斷網(wǎng)頁(yè)是否能后退,可以則goback() //2.如果不可以連續(xù)點(diǎn)擊兩次退出App,否則彈出提示Toast @Override public void onBackPressed() { if (webView.canGoBack()) { webView.goBack(); } else { if ((System.currentTimeMillis() - exitTime) > 2000) { Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show(); exitTime = System.currentTimeMillis(); } else { super.onBackPressed(); } } } }
2)布局代碼中設(shè)置WebView
相信大家都見(jiàn)過(guò)很多的新聞?lì)怉pp吧或者門戶信息類的App,他的結(jié)構(gòu)可能是這樣的:
左上角一個(gè)點(diǎn)擊關(guān)閉當(dāng)前Activity的按鈕,中間是新聞的title,右面是一個(gè)刷新按鈕, 而在右下角可能有這樣一個(gè)懸浮的按鈕,當(dāng)我們滑動(dòng)超過(guò)屏幕寬度他就會(huì)顯示出來(lái), 當(dāng)用戶點(diǎn)擊后又會(huì)回滾到網(wǎng)頁(yè)的頂部!下面我們來(lái)簡(jiǎn)單的實(shí)現(xiàn)下!
運(yùn)行效果圖:
實(shí)現(xiàn)代碼:
MainActivity.java:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_back; private TextView txt_title; private Button btn_top; private Button btn_refresh; private WebView wView; private long exitTime = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindViews(); } private void bindViews() { btn_back = (Button) findViewById(R.id.btn_back); txt_title = (TextView) findViewById(R.id.txt_title); btn_top = (Button) findViewById(R.id.btn_top); btn_refresh = (Button) findViewById(R.id.btn_refresh); wView = (WebView) findViewById(R.id.wView); btn_back.setOnClickListener(this); btn_refresh.setOnClickListener(this); btn_top.setOnClickListener(this); wView.loadUrl("http://www.baidu.com"); wView.setWebChromeClient(new WebChromeClient() { //這里設(shè)置獲取到的網(wǎng)站title @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); txt_title.setText(title); } }); wView.setWebViewClient(new WebViewClient() { //在webview里打開(kāi)新鏈接 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_back: finish(); //關(guān)閉當(dāng)前Activity break; case R.id.btn_refresh: wView.reload(); //刷新當(dāng)前頁(yè)面 break; case R.id.btn_top: wView.setScrollY(0); //滾動(dòng)到頂部 break; } } @Override public void onBackPressed() { if (wView.canGoBack()) { wView.goBack(); } else { if ((System.currentTimeMillis() - exitTime) > 2000) { Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show(); exitTime = System.currentTimeMillis(); } else { finish(); } } } }
問(wèn)題答疑:
相信細(xì)心的朋友看到,我們回到一開(kāi)始加載的頁(yè)面后,按返回鍵,按了多次還是沒(méi)有退出 當(dāng)前的APP,后來(lái)還是我們手動(dòng)去點(diǎn)back鍵通過(guò)調(diào)用finish方法才能關(guān)閉當(dāng)前的Activity? 這是為什么呢?明明百度一下已經(jīng)是第一個(gè)頁(yè)面???
答:其實(shí)發(fā)生這個(gè)的原因是:網(wǎng)址的重定向問(wèn)題引起的,其實(shí)我們?cè)谠L問(wèn)百度的時(shí)候:
盡管我們load的是www.baidu.com,但是百度做了重定向,跳轉(zhuǎn)到了手機(jī)版百度一下網(wǎng)頁(yè): 即實(shí)際你的流程是:www.baidu.com -> 手機(jī)版百度一下 -> 打開(kāi)其他的鏈接!
我們看到我們上面shouldOverrideUrlLoading()方法是這樣寫的:
view.loadUrl(url);return true;我們知道用戶點(diǎn)擊一次回退鍵,那么webview會(huì)調(diào)用一次goback方法(),我們把上面三個(gè) 設(shè)做A,B,C三個(gè)站點(diǎn),在C時(shí)點(diǎn)回退,C - > B沒(méi)問(wèn)題,接著再點(diǎn) B -> A,這個(gè)時(shí)候問(wèn)題 就來(lái)了盡管B來(lái)到了A,但是因?yàn)橹囟ㄏ蛴痔D(zhuǎn)到了B,如此循環(huán)往復(fù)...這就是為什么 點(diǎn)擊回退鍵并沒(méi)有推出WebView的原因,解決方法:手速,在webview未加載完網(wǎng)頁(yè) 錢連續(xù)雙擊回退鍵,手速要夠快,哈哈!說(shuō)笑而已,要解決這個(gè)問(wèn)題,我們只需將 shouldOverrideUrlLoading里的東東刪掉,然后寫上return false;即可! 不信是重定向,可以自己修改下URL試試~
需求2:WebView滾動(dòng)事件的監(jiān)聽(tīng)
我們都知道監(jiān)聽(tīng)滾動(dòng)事件一般都是設(shè)置setOnScrollChangedListener,可惜的是 WebView并沒(méi)有給我們提供這樣的方法,但是我們可以重寫WebView,覆蓋里面的一個(gè)方法: protected void onScrollChanged(final int l, final int t, final int oldl,final int oldt){} 然后再對(duì)外提供一個(gè)接口,示例代碼如下:
MyWebViewDemo.java:
/** * Created by Jay on 2015/9/11 0011. */ public class MyWebView extends WebView { private OnScrollChangedCallback mOnScrollChangedCallback; public MyWebView(Context context) { super(context); } public MyWebView(Context context, AttributeSet attrs) { super(context, attrs); } public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mOnScrollChangedCallback != null) { mOnScrollChangedCallback.onScroll(l - oldl, t - oldt); } } public OnScrollChangedCallback getOnScrollChangedCallback() { return mOnScrollChangedCallback; } public void setOnScrollChangedCallback( final OnScrollChangedCallback onScrollChangedCallback) { mOnScrollChangedCallback = onScrollChangedCallback; } public static interface OnScrollChangedCallback { //這里的dx和dy代表的是x軸和y軸上的偏移量,你也可以自己把l, t, oldl, oldt四個(gè)參數(shù)暴露出來(lái) public void onScroll(int dx, int dy); } }
MainActivity.java:
public class MainActivity extends AppCompatActivity { private MyWebView wView; private Button btn_icon; private long exitTime = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_icon = (Button) findViewById(R.id.btn_icon); wView = (MyWebView) findViewById(R.id.wView); wView.loadUrl("http://www.hao123.com"); wView.setWebViewClient(new WebViewClient() { //在webview里打開(kāi)新鏈接 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); //比如這里做一個(gè)簡(jiǎn)單的判斷,當(dāng)頁(yè)面發(fā)生滾動(dòng),顯示那個(gè)Button wView.setOnScrollChangedCallback(new MyWebView.OnScrollChangedCallback() { @Override public void onScroll(int dx, int dy) { if (dy > 0) { btn_icon.setVisibility(View.VISIBLE); } else { btn_icon.setVisibility(View.GONE); } } }); btn_icon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { wView.setScrollY(0); btn_icon.setVisibility(View.GONE); } }); } @Override public void onBackPressed() { if (wView.canGoBack()) { wView.goBack(); } else { if ((System.currentTimeMillis() - exitTime) > 2000) { Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show(); exitTime = System.currentTimeMillis(); } else { finish(); } } } }
運(yùn)行效果圖:
當(dāng)網(wǎng)頁(yè)開(kāi)始滾動(dòng),會(huì)呈現(xiàn)一個(gè)呵呵的按鈕,我們點(diǎn)擊呵呵按鈕可以回到頂部! 然后呵呵按鈕會(huì)隱藏~
需求3:滾動(dòng)條的問(wèn)題
你可能用的屬性如下:
- setHorizontalScrollBarEnabled(false);//水平不顯示
- setVerticalScrollBarEnabled(false); //垂直不顯示
- setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);//滾動(dòng)條在WebView內(nèi)側(cè)顯示
- setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY)//滾動(dòng)條在WebView外側(cè)顯示
需求4:設(shè)置縮放以及自適應(yīng)屏幕
根據(jù)我們一般的習(xí)慣打開(kāi)網(wǎng)頁(yè)對(duì)于看不清楚的地方,我們喜歡雙指來(lái)縮放網(wǎng)頁(yè),而WebView 則需要我們自己手動(dòng)來(lái)設(shè)置這個(gè)是否支持縮放了!
只需要在加入下述代碼即可:
WebSettings settings = wView.getSettings(); settings.setUseWideViewPort(true);//設(shè)定支持viewport settings.setLoadWithOverviewMode(true); //自適應(yīng)屏幕 settings.setBuiltInZoomControls(true); settings.setDisplayZoomControls(false); settings.setSupportZoom(true);//設(shè)定支持縮放
使用上述代碼后,進(jìn)去頁(yè)面就會(huì)是這樣一個(gè)效果:
當(dāng)我們縮放時(shí),出現(xiàn)了一個(gè)惡心的問(wèn)題,就是很常見(jiàn)的縮放控件,我們肯定是不想要的啦, 那么加上下面句代碼就可以把縮放控件給隱藏掉了!
settings.setDisplayZoomControls(false);
我們也可以自行設(shè)置初始的縮放比例,只需為webView:
wView.setInitialScale(25);//為25%,最小縮放等級(jí)
嘿嘿,上面是整個(gè)網(wǎng)頁(yè)都縮放的,不過(guò)可能有時(shí)我們僅僅是需要對(duì)字體進(jìn)行縮放,那么可以 這樣做:
settings.setTextZoom(int);
也可以直接通過(guò):
settings.setTextSize(TextSize.LARGER);
來(lái)設(shè)置大小。
Android自帶五個(gè)可選字體大小的值:SMALLEST(50%),SMALLER(75%),NORMAL(100%),LARGER(150%), LARGEST(200%)。
需求5.獲取WebView的Cookie數(shù)據(jù)
我們都知道Cookie其實(shí)只是一個(gè)代表用戶唯一標(biāo)識(shí)的字符串,情景一般是: 用戶輸入賬號(hào)密碼后,點(diǎn)擊登陸,用戶要拿著這個(gè)Cookie去訪問(wèn)服務(wù)器提供的相關(guān)服務(wù)! 我們可以把cookie的獲取寫到onPageFinsihed的方法中,簡(jiǎn)單的可以這樣寫:
@Override public void onPageFinished(WebView view, String url) { CookieManager cookieManager = CookieManager.getInstance(); String CookieStr = cookieManager.getCookie(url); Log.e("HEHE", "Cookies = " + CookieStr); super.onPageFinished(view, url); }
需求6.設(shè)置WebView的Cookie數(shù)據(jù)
嘿嘿,我們上面獲取到了Cookie或者通過(guò)其他途徑獲得了Cookie,我們?nèi)绾螢閃ebView設(shè)置Cookie呢? 我們可以在需要設(shè)置Cookie的地方加入下述代碼:
CookieSyncManager.createInstance(MainActivity.this); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); cookieManager.setCookie(url, cookies); //cookies是要設(shè)置的cookie字符串 CookieSyncManager.getInstance().sync();
對(duì)了,上述代碼需要寫在loadUrl()之前,而且如果設(shè)置了Cookie了,盡量別再進(jìn)行其他的設(shè)置 不然可能會(huì)無(wú)效,建議設(shè)置cookie的寫在webView相關(guān)設(shè)置的最后面~loadUrl()之前!
4.示例代碼下載:
WebViewDemo1:下載 WebViewDemo1.zip
WebViewDemo2:下載 WebViewDemo2.zip
本節(jié)小結(jié):
好的,本節(jié)給大家介紹了一下WebView的基本用法,加載網(wǎng)頁(yè),設(shè)置縮放,字體縮放, 自適應(yīng)屏幕,以及Cookie的獲取以及設(shè)置;相信日常開(kāi)發(fā)中還有各種奇葩的需求,不過(guò) 限于篇幅就寫這么多,有idea的歡迎留言,下節(jié)我們來(lái)學(xué)習(xí)HTML5端如何通過(guò)JavaScript 來(lái)與WebView交互,并獲取手機(jī)的相關(guān)數(shù)據(jù)!敬請(qǐng)期待~謝謝~