WebView(網頁檢視)基本用法


本節引言

本節帶給大家的是Android中的一個用來顯示網頁的控制項:WebView(網頁視圖)。

現在Android應用 層開發的方向有兩種:客戶端開發和HTML5行動端開發!

所謂的HTML5端就是:HTML5 + CSS + JS來構建 一個網頁版的應用,而這中間的媒介就是這個WebView,而Web和網頁端可以透過JS來進行互動,比如, 網頁讀取手機聯絡人,呼叫手機相關的API等!

而且比起普通的客戶端開發,HTML5行動端有個優勢: 可以用百分比來佈局,而且如果HTML5端有什麼大改,我們不用像客戶端那樣去重新下一個APP,然後 覆蓋安裝,我們只需修改下網頁即可!而客戶端...慘不忍睹,當然HTML5也有個缺點,就是效能的問題, 資料累積,耗電問題,還有閃屏等等...

另外,針對這種跨平台我們可以使用其他的第三方快速開發 框架,例如PhoneGap,對了,還有現在網路上很多一鍵生成APP類的網站,用戶透過拖拉,設定圖片 之類的簡單操作就可以產生一個應用,大部分都是用的HTML5來完成的!有模板,直接套,你懂的~ 好的,話不多說,開始本節內容!

1.什麼是WebView?

答案:Android內建webkit核心的高效能瀏覽器,而WebView則是在這個基礎上進行封裝後的一個 控制,WebView直譯網頁視圖,我們可以簡單的看作一個可以嵌套到介面上的一個瀏覽器控制項!

2.相關方法

先上官方文檔:WebView並不打算一個個地去講屬性,用到哪個寫哪個,其他的自行查閱文件! 除了直接WebView外我們還可以加入你自己的行為,可以自行自訂下述類別:


#WebChromeClient:輔助WebView處理Javascript的對話框、網站圖標、網站title、載入進度等! 比如下面這些:

方法作用
#onJsAlert(WebView view,String url,String message,JsResult result)處理Js中的Alert對話框
onJsConfirm(WebView view,String url,String message, JsResult result)處理Js中的Confirm對話框
onJsPrompt(WebView view,String url,String message,String defaultValue,JsPromptResult result )處理Js中的Prompt對話框
onProgressChanged(WebView view,int newProgress)當載入進度條改變時呼叫
onReceivedIcon(WebView view, Bitmap icon)取得網頁的icon
#onReceivedTitle(WebView view, String title)#取得網頁的標題

##WebViewClient:輔助WebView處理各種通知與請求事件! 例如下面這些方法:

方法作用通知主程式網頁開始載入通知主程式,網頁載入完成#更新歷史記錄通知主程式WebView即將載入指定url的資源ViewView的縮放發生變更時呼叫控制webView是否處理按鍵時間,如果返回true,則WebView不處理,返回false則處理#shouldOverrideUrlLoading(WebView view,String url)
onPageStared (WebView view,String url)
onPageFinished(WebView view,String url,Bitmap favicon )
doUpdateVisitedHistory(WebView view,String url,boolean isReload)
onLoadResource(WebView view,String url)
#onScaleChanged(WebView view,float oldScale,float newScale)
#shouldOverrideKeyEvent(WebView view,KeyEvent event)
####控制對新載入的Url的處理,傳回true,說明主程式處理WebView不做處理,傳回false意味著WebView會對其進行處理###############onReceivedError###(WebView view,int errorCode,String description,String failingUrl)#######當遇到不可恢復的錯誤訊息時呼叫## ##########

WebSettings:WebView相關配置的設置,例如setJavaScriptEnabled()設定是否允許JS腳本執行 部分方法如下:

方法作用
getSettings()回傳一個WebSettings物件,用來控制WebView的屬性設定
#loadUrl(String url) #載入指定的Url
loadData(String data,String mimeType,String encoding)載入指定的Data到WebView中.使用" data:"作為標記頭,此方法不能載入網路資料.其中mimeType為資料型別如:textml,image/jpeg. encoding為字元的編碼方式
loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)#比上面的loadData更強大
setWebViewClient( WebViewClient client)為WebView指定一個WebViewClient物件.WebViewClient可以輔助WebView處理各種通知,請求等事件。
setWebChromeClient(WebChromeClient client)為WebView指定一個WebChromeClient物件,WebChromeClient專門用來輔助WebView處理js的對話方塊,網站title ,網站圖示,載入進度條等

這裡重要區分三個load方法的差異:

loadUrl():直接顯示網頁內容(單獨顯示網頁圖片),一般不會出現亂碼。 loadData(data, "text/html", "UTF-8"):用來載入URI格式的數據,不能透過網路來載入內容, 不能載入圖片,而且常常會遇到亂碼的問題,我們知道String類型的資料主要是Unicode編碼的, 而WebView一般為了節省資源使用的是UTF-8編碼,儘管我們照上面寫了,但還需要設定webView: webview.getSettings().setDefaultTextEncodingName("UTF -8");loadDataWithBaseURL(baseUrl, string, "text/html", "utf-8", null):loadData類別的一個 增強類,可以載入圖片,baseUrl為你儲存的圖片路徑,而且只要在這裡設定utf-8就可以解決亂碼 問題了!

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

WebChromeClient文件

##WebViewClient文件

WebSettings文件


#3.一些常見需求講解

需求1:根據URL載入網頁

1)直接在Activity上載入一個WebView

運行效果圖

1.gif

實現代碼

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() {
            //设置在webView点击打开的新网页在当前界面显示,而不跳转到新的浏览器中
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });
        webView.getSettings().setJavaScriptEnabled(true);  //设置WebView属性,运行执行js脚本
        webView.loadUrl("http://www.baidu.com/");          //调用loadView方法为WebView加入链接
        setContentView(webView);                           //调用Activity提供的setContentView将webView显示出来
    }


    //我们需要重写回退按钮的时间,当用户点击回退按钮:
    //1.webView.canGoBack()判断网页是否能后退,可以则goback()
    //2.如果不可以连续点击两次退出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)佈局程式碼中設定WebView

相信大家都看過很多的新聞類App吧或入口網站訊息類別的App,他的結構可能是這樣的:

2.png

左上角一個點擊關閉當前Activity的按鈕,中間是新聞的title,右面是一個刷新按鈕, 而在右下角可能有這樣一個懸浮的按鈕,當我們滑動超過螢幕寬度他就會顯示出來, 當使用者點擊後又會回滾到網頁的頂部!下面我們就來簡單的實作下吧!

執行效果圖

3.gif

#實作程式碼

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() {
            //这里设置获取到的网站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();          //关闭当前Activity
                break;
            case R.id.btn_refresh:
                wView.reload();    //刷新当前页面
                break;
            case R.id.btn_top:
                wView.setScrollY(0);   //滚动到顶部
                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();
            }

        }
    }
}

問題答案

#相信細心的朋友看到​​,我們回到一開始載入的頁面後,按回傳鍵,按了多次還是沒有退出 目前的APP,後來還是我們手動去點back鍵透過呼叫finish方法才能關閉目前的Activity? 這是為什麼呢?明明百度一下已經是第一個頁面啊?

答:其實發生這個的原因是:網址的重定向問題引起的,其實我們在訪問百度的時候:

#儘管我們load的是www.baidu.com,但是百度做了重定向,跳到手機版百度一下網頁了: 即實際你的流程是:www.baidu.com -> 手機版百度一下 -> 打開其他的連結!

我們看到我們上面shouldOverrideUrlLoading()方法是這樣寫的:

view.loadUrl(url);return true;我們知道用戶點擊一次回退鍵,那麼webview會呼叫一次goback方法(),我們把上面三個 設做A,B,C三個站點,在C時點回退,C - > B沒問題,接著再點 B -> A,這個時候問題 就來了儘管B來到了A,但是因為重定向又跳到了B,如此循環往復...這就是為什麼 點選回退鍵並沒有推出WebView的原因,解決方法:手速,在webview未載入完網頁 錢連續雙擊回退鍵,手速要夠快,哈哈!說笑而已,要解決這個問題,我們只需將 shouldOverrideUrlLoading裡的東東刪掉,然後寫上return false;即可! 不信是重定向,可以自己修改下URL試試~


需求2:WebView滾動事件的監聽

#我們都知道監聽滾動事件一般都是設定setOnScrollChangedListener ,可惜的是 WebView並沒有提供我們這樣的方法,但是我們可以重寫WebView,覆寫裡面的一個方法: protected void onScrollChanged(final int l, final int t, final int oldl,final int oldt){} 然後再對外提供一個接口,範例程式碼如下:

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四个参数暴露出来
        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;
            }
        });

        //比如这里做一个简单的判断,当页面发生滚动,显示那个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();
            }

        }
    }
}

運行效果圖

4.gif

當網頁開始捲動,會呈現一個呵呵的按鈕,我們點擊呵呵按鈕可以回到頂部! 然後呵呵按鈕會隱藏~


需求3:滾動條的問題

你可能用的屬性如下:

    ##setHorizo​​ntalScrollBarEnabled(false );//水平不顯示
  • setVerticalScrollBarEnabled(false); //垂直不顯示
  • setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);//捲軸在WebView內側顯示
  • setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY)//捲軸在WebView外側顯示

需求4:設定縮放以及自適應螢幕

#根據我們一般的習慣開啟網頁對於看不清楚的地方,我們喜歡雙指來縮放網頁,而WebView 則需要我們自己手動來設定這個是否支援縮放了!

只需要在加入下述程式碼即可:

WebSettings settings = wView.getSettings();
settings.setUseWideViewPort(true);//设定支持viewport
settings.setLoadWithOverviewMode(true);   //自适应屏幕
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(false);
settings.setSupportZoom(true);//设定支持缩放

使用上述程式碼後,進去頁面就會是這樣一個效果:

5.png

當我們縮放時,出現了一個噁心的問題,就是很常見的縮放控件,我們肯定是不想要的啦, 那麼加上下面句程式碼就可以把縮放控制項給隱藏掉了!

settings.setDisplayZoomControls(false);

我們也可以自行設定初始的縮放比例,只需為webView:

wView.setInitialScale(25);//为25%,最小缩放等级

嘿嘿,上面是整個網頁都縮放的,不過可能有時我們只是需要對字體進行縮放,那麼可以 這樣做:

settings.setTextZoom(int);

也可以直接透過:

settings.setTextSize(TextSize.LARGER);

來設定大小。

Android自帶五個可選字體大小的值:SMALLEST(50%),SMALLER(75%),NORMAL(100%),LARGER(150%), LARGEST(200%)。


需求5.取得WebView的Cookie資料

我們都知道Cookie其實只是一個代表使用者唯一識別的字串,情境一般是: 使用者輸入帳號密碼後,點選登陸,使用者要拿著這個Cookie去存取伺服器提供的相關服務! 我們可以把cookie的獲取寫到onPageFinsihed的方法中,簡單的可以這樣寫:

@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.設定WebView的Cookie資料

嘿嘿,我們上面取得了Cookie或是透過其他途徑獲得了Cookie,我們如何為WebView設定Cookie呢? 我們可以在需要設定Cookie的地方加入下述程式碼:

CookieSyncManager.createInstance(MainActivity.this);  
CookieManager cookieManager = CookieManager.getInstance();  
cookieManager.setAcceptCookie(true);  
cookieManager.setCookie(url, cookies);  //cookies是要设置的cookie字符串 
CookieSyncManager.getInstance().sync();

對了,上述程式碼需要寫在loadUrl()之前,而且如果設定了Cookie了,盡量別再進行其他的設置 不然可能會無效,建議設定cookie的寫在webView相關設定的最後面~loadUrl()之前!


4.範例程式碼下載:

WebViewDemo1:下載WebViewDemo1.zip

WebViewDemo2:下載WebViewDemo2.zip


本節小結:

#好的,本節跟大家介紹了一下WebView的基本用法,載入網頁,設定縮放,字體縮放, 自適應螢幕,以及Cookie的取得以及設定;相信日常開發中還有各種奇葩的需求,不過 限於篇幅就寫這麼多,有idea的歡迎留言,下節我們來學習HTML5端如何透過JavaScript 來與WebView交互,並取得手機的相關數據!敬請期待~謝謝~

#