Android WebView(網(wǎng)頁視圖)基本用法

2023-03-31 14:16 更新

本節(jié)引言

本節(jié)給大家?guī)淼氖茿ndroid中的一個(gè)用于顯示網(wǎng)頁的控件:WebView(網(wǎng)頁視圖)。

現(xiàn)在Android應(yīng)用 層開發(fā)的方向有兩種:客戶端開發(fā)和HTML5移動(dòng)端開發(fā)!

所謂的HTML5端就是:HTML5 + CSS + JS來構(gòu)建 一個(gè)網(wǎng)頁版的應(yīng)用,而這中間的媒介就是這個(gè)WebView,而Web和網(wǎng)頁端可以通過JS來進(jìn)行交互,比如, 網(wǎng)頁讀取手機(jī)聯(lián)系人,調(diào)用手機(jī)相關(guān)的API等!

而且相比起普通的客戶端開發(fā),HTML5移動(dòng)端有個(gè)優(yōu)勢(shì): 可以用百分比來布局,而且如果HTML5端有什么大改,我們不用像客戶端那樣去重新下一個(gè)APP,然后 覆蓋安裝,我們只需修改下網(wǎng)頁即可!而客戶端...慘不忍睹,當(dāng)然HTML5也有個(gè)缺點(diǎn),就是性能的問題, 數(shù)據(jù)積累,耗電問題,還有閃屏等等...

另外,針對(duì)這種跨平臺(tái)我們可以使用其他的第三方快速開發(fā) 框架,比如PhoneGap,對(duì)了,還有現(xiàn)在網(wǎng)絡(luò)上很多一鍵生成APP類的網(wǎng)站,用戶通過拖拉,設(shè)置圖片 之類的簡(jiǎn)單操作就可以生成一個(gè)應(yīng)用,大部分都是用的HTML5來完成的!有模板,直接套,你懂的~ 好的,話不多說,開始本節(jié)內(nèi)容!

1.什么是WebView?

答:Android內(nèi)置webkit內(nèi)核的高性能瀏覽器,而WebView則是在這個(gè)基礎(chǔ)上進(jìn)行封裝后的一個(gè) 控件,WebView直譯網(wǎng)頁視圖,我們可以簡(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)頁的icon
onReceivedTitle(WebView view, String title) 獲得網(wǎng)頁的標(biāo)題

WebViewClient:輔助WebView處理各種通知與請(qǐng)求事件! 比如下面這些方法:

方法 作用
onPageStared(WebView view,String url) 通知主程序網(wǎng)頁開始加載
onPageFinished(WebView view,String url,Bitmap favicon) 通知主程序,網(wǎng)頁加載完畢
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,說明主程序處理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ì)象,用來控制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專門用來輔助WebView處理js的對(duì)話框,網(wǎng)站title,網(wǎng)站圖標(biāo),加載進(jìn)度條等

這里重要區(qū)分三個(gè)load方法的區(qū)別:

loadUrl():直接顯示網(wǎng)頁內(nèi)容(單獨(dú)顯示網(wǎng)絡(luò)圖片),一般不會(huì)出現(xiàn)亂碼。 loadData(data, "text/html", "UTF-8"):用來加載URI格式的數(shù)據(jù),不能通過網(wǎng)絡(luò)來加載內(nèi)容, 不能加載圖片,而且經(jīng)常會(huì)遇到亂碼的問題,我們知道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就可以解決亂碼 問題了!

這里只是列舉了部分屬性而已,其他的還需自行查閱官方文檔:

WebChromeClient文檔

WebViewClient文檔

WebSettings文檔


3.一些常見需求講解

需求1:根據(jù)URL加載網(wǎng)頁

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)擊打開的新網(wǎng)頁在當(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顯示出來
    }

    //我們需要重寫回退按鈕的時(shí)間,當(dāng)用戶點(diǎn)擊回退按鈕:
    //1.webView.canGoBack()判斷網(wǎng)頁是否能后退,可以則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

相信大家都見過很多的新聞?lì)怉pp吧或者門戶信息類的App,他的結(jié)構(gòu)可能是這樣的:

左上角一個(gè)點(diǎn)擊關(guān)閉當(dāng)前Activity的按鈕,中間是新聞的title,右面是一個(gè)刷新按鈕, 而在右下角可能有這樣一個(gè)懸浮的按鈕,當(dāng)我們滑動(dòng)超過屏幕寬度他就會(huì)顯示出來, 當(dāng)用戶點(diǎn)擊后又會(huì)回滾到網(wǎng)頁的頂部!下面我們來簡(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里打開新鏈接
            @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)前頁面
                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();
            }

        }
    }
}

問題答疑

相信細(xì)心的朋友看到,我們回到一開始加載的頁面后,按返回鍵,按了多次還是沒有退出 當(dāng)前的APP,后來還是我們手動(dòng)去點(diǎn)back鍵通過調(diào)用finish方法才能關(guān)閉當(dāng)前的Activity? 這是為什么呢?明明百度一下已經(jīng)是第一個(gè)頁面???

答:其實(shí)發(fā)生這個(gè)的原因是:網(wǎng)址的重定向問題引起的,其實(shí)我們?cè)谠L問百度的時(shí)候:

盡管我們load的是www.baidu.com,但是百度做了重定向,跳轉(zhuǎn)到了手機(jī)版百度一下網(wǎng)頁: 即實(shí)際你的流程是:www.baidu.com -> 手機(jī)版百度一下 -> 打開其他的鏈接!

我們看到我們上面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沒問題,接著再點(diǎn) B -> A,這個(gè)時(shí)候問題 就來了盡管B來到了A,但是因?yàn)橹囟ㄏ蛴痔D(zhuǎn)到了B,如此循環(huán)往復(fù)...這就是為什么 點(diǎn)擊回退鍵并沒有推出WebView的原因,解決方法:手速,在webview未加載完網(wǎng)頁 錢連續(xù)雙擊回退鍵,手速要夠快,哈哈!說笑而已,要解決這個(gè)問題,我們只需將 shouldOverrideUrlLoading里的東東刪掉,然后寫上return false;即可! 不信是重定向,可以自己修改下URL試試~


需求2:WebView滾動(dòng)事件的監(jiān)聽

我們都知道監(jiān)聽滾動(dòng)事件一般都是設(shè)置setOnScrollChangedListener,可惜的是 WebView并沒有給我們提供這樣的方法,但是我們可以重寫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ù)暴露出來
        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里打開新鏈接
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });

        //比如這里做一個(gè)簡(jiǎn)單的判斷,當(dāng)頁面發(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)頁開始滾動(dòng),會(huì)呈現(xiàn)一個(gè)呵呵的按鈕,我們點(diǎn)擊呵呵按鈕可以回到頂部! 然后呵呵按鈕會(huì)隱藏~


需求3:滾動(dòng)條的問題

你可能用的屬性如下:

  • 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í)慣打開網(wǎng)頁對(duì)于看不清楚的地方,我們喜歡雙指來縮放網(wǎng)頁,而WebView 則需要我們自己手動(dòng)來設(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)去頁面就會(huì)是這樣一個(gè)效果:

當(dāng)我們縮放時(shí),出現(xiàn)了一個(gè)惡心的問題,就是很常見的縮放控件,我們肯定是不想要的啦, 那么加上下面句代碼就可以把縮放控件給隱藏掉了!

settings.setDisplayZoomControls(false);

我們也可以自行設(shè)置初始的縮放比例,只需為webView:

wView.setInitialScale(25);//為25%,最小縮放等級(jí)

嘿嘿,上面是整個(gè)網(wǎng)頁都縮放的,不過可能有時(shí)我們僅僅是需要對(duì)字體進(jìn)行縮放,那么可以 這樣做:

settings.setTextZoom(int);

也可以直接通過:

settings.setTextSize(TextSize.LARGER);

來設(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ù)器提供的相關(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或者通過其他途徑獲得了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ì)無效,建議設(shè)置cookie的寫在webView相關(guān)設(shè)置的最后面~loadUrl()之前!


4.示例代碼下載:

WebViewDemo1:下載 WebViewDemo1.zip

WebViewDemo2:下載 WebViewDemo2.zip


本節(jié)小結(jié):

好的,本節(jié)給大家介紹了一下WebView的基本用法,加載網(wǎng)頁,設(shè)置縮放,字體縮放, 自適應(yīng)屏幕,以及Cookie的獲取以及設(shè)置;相信日常開發(fā)中還有各種奇葩的需求,不過 限于篇幅就寫這么多,有idea的歡迎留言,下節(jié)我們來學(xué)習(xí)HTML5端如何通過JavaScript 來與WebView交互,并獲取手機(jī)的相關(guān)數(shù)據(jù)!敬請(qǐng)期待~謝謝~


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)