Android 用WebView開發簡單的瀏覽器

CAFE_BABE發表於2017-12-19

Android   用WebView開發簡單的瀏覽器
Android-用WebView開發簡單的瀏覽器

Android 提供了 WebView 元件,WebView 本身就是一個瀏覽器實現。

例子中主要用到了 WebView 的以下方法:

  • void loadUrl(String url) 載入指定 url 對應的網頁
  • void goBack() 後退
  • void goForward() 前進
  • boolean canGoBack() 根據歷史記錄判斷是否可以回退
  • boolean canGoForward() 根據歷史記錄判斷是否可以前進
  • WebSettings getSettings() 獲得對 WebView 進行控制的 WebSettings 物件 (呼叫其setJavaScriptEnabled方法使WebView支援JavaScript
  • void setWebViewClient(WebViewClient client) WebViewClient 負責處理 WebView 各種通知,請求,比如頁面開始載入及載入完成、資源載入中、url已開啟等
  • void setWebChromeClient(WebChromeClient client) WebChromeClient主要輔助WebView處理Javascript的對話方塊、網站圖示、網站title、載入進度

瀏覽器功能概述:

  1. 第一次開啟應用時預設會把百度設定為首頁,可通過底部主頁按鈕跳轉到主頁,或通過長按彈出對話方塊修改主頁
  2. 主頁的 URL 地址使用SharedPreference儲存
  3. 底部四個ImageButton從做往右依次為主頁 重新整理 回退 前進
  4. 頂部的ActionBarvoid setCustomView(View)新增了一個自定義的用於輸入網址的輸入框和一個轉到按鈕,轉到按鈕預設是不可見且不可用的,當點選了用於輸入網址EditText就會顯示並可用。
  5. 用於顯示網頁載入進度的ProgressBar

截圖

這裡寫圖片描述

程式碼部分

  • 每次開啟一個網頁時會呼叫該方法,在這裡控制ActionBar內的Edittext顯示載入中...
 mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                mShowTitle.setText("載入中...");
            }
            ...
}
複製程式碼
  • 覆寫shouldOverrideUrlLoading並返回true,否則 WebView 預設會呼叫系統的瀏覽器或第三方瀏覽器,而不使用當前activity中的WebView
mWebView.setWebViewClient(new WebViewClient() {
			...
			@Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
		    ...
}
複製程式碼
  • 當網頁載入進度改變時會回撥onProgressChanged方法,在這裡更新用於顯示進度的ProgressBar。注意newProgress值為 0 到 100 ,因而將ProgressBar最大值設為 100 。
  • onReceivedTitle返回當前載入網頁的標題將標題顯示在 actionBar 內的 EditText 上。
mWebView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                mProgressBar.setProgress(newProgress);
                if (newProgress == 100) {
                    mProgressBar.postDelayed(() -> mProgressBar.setProgress(0), 2000);
                }
        }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);
                currentUrlTitle = title;
                mShowTitle.setText(currentUrlTitle);
            }
        });
複製程式碼
  • 監聽物理按鍵返回的點選事件,如果WebView歷史記錄裡有上一頁相關記錄就呼叫void goBack()方法
@Override
    public void onBackPressed() {
        if (mWebView.canGoBack())
            mWebView.goBack();
        else finish();
    }
複製程式碼
  • 判斷當前是否處於正在輸入網址(actionBar上的 EditText)的狀態 1 是的話呼叫此方法表示輸入結束從使轉到按鈕消失並不可用 2 使EditText控制元件失去焦點,不然會一直顯示游標,效果不好
private void finishEdit() {
        if (isEditFocus) {
            isEditFocus = false;
            mShowTitle.clearFocus();

            Animation animation = AnimationUtils.loadAnimation(MainActivity.this, android.R.anim.fade_out);
            animation.setFillAfter(true);
            mLoadUrl.startAnimation(animation);
            mLoadUrl.setEnabled(false);

            mShowTitle.setText(currentUrlTitle);
        }
    }
複製程式碼

這個方法有三個地方呼叫到: 1 當正在輸入網址時使用者轉移注意力到WebView上,並觸控到WebView,此時會先判斷軟鍵盤是否正在顯示,正在顯示就關閉軟鍵盤然後使輸入框失去焦點並隱藏轉到按鈕

 mWebView.setOnTouchListener((View view, MotionEvent event) -> {
       if (event.getAction() == MotionEvent.ACTION_DOWN) {
           finishEdit();
           InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
           if (imm.isActive())
               imm.hideSoftInputFromWindow(mShowTitle.getWindowToken(),0);

       }
       return false;
   });

複製程式碼

2 當正在輸入網址時點選了物理按鍵返回,此時void onBackPressed()方法是不會被呼叫的,因為此時軟鍵盤正在顯示,呼叫boolean dispatchKeyEvent(KeyEvent event)方法攔截返回按鍵的點選事件,關閉軟鍵盤的同時使輸入框失去焦點並隱藏轉到按鈕。

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
            finishEdit();
        return super.dispatchKeyEvent(event);
    }
複製程式碼

3 點選了 actionBar 處的轉到按鈕 3.1 此時要先判斷是否正確輸入,然後判斷輸入網址是否是新的(和當前正在顯示的網頁的網址不同),滿足就讓WebView載入該網頁 3.2 判斷軟鍵盤是否正在顯示,正在顯示就關閉軟鍵盤然後使輸入框失去焦點並隱藏轉到按鈕

以下程式碼包含所有按鈕的點選事件,每個按鈕都在xml中新增了 android:onClick="onClick"屬性

 public void onClick(View view) {
        switch (view.getId()) {
            case R.id.main_goBack:
                if (mWebView.canGoBack())
                    mWebView.goBack();
                break;
            case R.id.main_goForward:
                if (mWebView.canGoForward())
                    mWebView.goForward();
                break;
            case R.id.main_refresh:
                mWebView.loadUrl(currentUrl);
                break;
            case R.id.actionBar_goto:
                String url = mShowTitle.getText().toString() == "" ? null : mShowTitle.getText().toString().equals(currentUrl) ? null : mShowTitle.getText().toString();
                if (url != null)
                    mWebView.loadUrl(url);

                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm.isActive())
                    imm.hideSoftInputFromWindow(mShowTitle.getWindowToken(),0);

                finishEdit();
                break;
            case R.id.main_home:
                if (!currentUrl.equals(homeUrl))
                    mWebView.loadUrl(homeUrl);
                break;
        }
    }
複製程式碼

值得注意的地方:

  • 在style中使用colorControlHighlight屬性改變預設的按鈕點選波紋效果的顏色 比如這樣:
<item name="colorControlHighlight">@color/colorPrimary</item>
複製程式碼
  • 在按鈕的xml屬性中通過設定
style=`"@style/Base.Widget.AppCompat.Button.Borderless.Colored"
複製程式碼

使按鈕的點選效果不受佈局邊界限制。其他預設不可點選的view(如EditText,TextView等)還要在新增一個:

android:clickable="true"
複製程式碼
  • 使用到的圖示在這裡下載的:Material icons - Material Design
  • 呼叫ActionBarsetCustomView方法前先要呼叫setDisplayShowCustomEnabled方法並置為true。
  • 修改主頁用到了對話方塊:
 AlertDialog.Builder builder
	 .setTitle("修改主頁")
     .setNegativeButton("取消", (DialogInterface dialog, int which) -> dialog.dismiss())
複製程式碼

這裡本來是用new DialogInterface.OnClickListener() {...}的形式寫的,後來改成使用Lambda的方式,這時要在app的build.gradle里加上:

android {
    ...
        jackOptions {
            enabled true
        }
        ...
    }
    ...
    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }
    ...
}
複製程式碼

相關文章