Android Webview和ScrollView衝突和WebView使用總結

滕玉坤發表於2019-03-04

更新:

前言:

今天review專案中的程式碼想起來之前修改一個有關Webview和ScrollView衝突的bug:

  • 1.因為Webview和ScrollView都用滑動事件,導致webview很難被滑動,即使被滑動了一點也非常不順暢
  • 2.解決滑動衝突問題後發現,如果webview巢狀的html中含有輪播圖等還是有問題。

Android Webview和ScrollView衝突和WebView使用總結

解決方案:

其實這兩個問題屬於同一類的問題,都是Webview和ScrollView滑動時產生的衝突 解決方法很簡單:

public class ScrollWebView extends WebView{
    private float startx;
    private float starty;
    private float offsetx;
    private float offsety;

    public ScrollWebView(Context context) {
        super(context);
    }

    public ScrollWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                startx = event.getX();
                starty = event.getY();
                Log.e("MotionEvent", "webview按下");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e("MotionEvent", "webview滑動");
                offsetx = Math.abs(event.getX() - startx);
                offsety = Math.abs(event.getY() - starty);
                if (offsetx > offsety) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                    Log.e("MotionEvent", "遮蔽了父控制元件");
                } else {
                    getParent().requestDisallowInterceptTouchEvent(false);
                    Log.e("MotionEvent", "事件傳遞給父控制元件");
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }
}
複製程式碼

自定義一個WebView,重寫onTouchEvent方法。判斷當手指橫向滑動的偏移量(offsetx)大於縱向滑動的偏移量(offsety)時遮蔽父控制元件的滑動。 解決方法很簡單,只要我們在遇到問題的時候多多思考,弄清楚錯誤的原因,有針對性的研究,絕大數的問題都是可以解決的。

webview使用總結

本來寫到這裡就想結束了,但是發現寫的東西太少了,估計會被罵,既然寫的是webview,索性就把我對webview的使用總結整理一下。

資料載入

  • 載入本地資源 webView.loadUrl("file:///android_asset/text.html");
  • 載入網路資源 webView.loadUrl("www.xxx.com/text.html");
  • 新增請求頭資訊 Map<String,String> map=new HashMap<String,String>(); map.put("User-Agent","Android"); webView.loadUrl("www.xxx.com/text.html",map);
  • 直接載入html程式碼片段 String html = "資料"; webView.loadDataWithBaseURL(null,html, "text/html", "utf-8",null);

支援JavaScript

  • 設定支援JavaScript WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true);//設定支援javascript webView.addJavascriptInterface(new JavaScriptInterface(), "tyk");//新增一個物件, 讓JS可以訪問該物件的方法, 該物件中可以呼叫JS中的方法

  • JavaScriptInterface 介面定義 private final class JavaScriptInterface {
    //JavaScript呼叫此方法撥打電話
    public void call(String phone) {
    //startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phone)));
    Toast.makeText(MainActivity.this, phone, Toast.LENGTH_LONG).show();
    }

          //Html呼叫此方法傳遞資料  
          public void showcontacts() {  
              String json = "[{\"name\":\"tyk\", \"amount\":\"9999999\", \"phone\":\"1831041486.\"}]";   
              // 呼叫JS中的方法  
              webView.loadUrl("javascript:show('" + json + "')");  
          }  
      }  
    複製程式碼

WebViewClient

  • 主要輔助WebView處理各種通知、請求事件 onLoadResource//載入資源時響應 onPageStart//在載入頁面時響應 onPageFinish//在載入頁面結束時響應 onReceiveError//在載入出錯時響應 onReceivedHttpAuthRequest//獲取返回資訊授權請求

  • 要實現WebView中連結在WebView內部跳轉

      webView.setWebViewClient(new WebViewClient() {
          public boolean shouldOverrideUrlLoading(WebView view, String url) {
              view.loadUrl(url);
              return true;
          }
      });
    複製程式碼

WebChromeClient

  • 主要輔助WebView處理Javascript的對話方塊,網站圖示,網站title,載入進度等   onCloseWindow//關閉WebView   onCreateWindow() //觸發建立一個新的視窗   onJsAlert //觸發彈出一個對話方塊   onJsPrompt //觸發彈出一個提示   onJsConfirm//觸發彈出確認提示   onProgressChanged //載入進度   onReceivedIcon //獲取網頁icon   onReceivedTitle//獲取網頁title

  • 載入進度獲取title

      webView.setWebChromeClient(new WebChromeClient() {
          @Override
          public void onProgressChanged(WebView view, int newProgress) {
              if (newProgress == 100) {
                  //網頁載入完成
              } else {
                  //網頁載入中
              }
          }
      });
    複製程式碼

WebView 快取控制

    LOAD_CACHE_ONLY//不使用網路,只讀取本地快取資料
    LOAD_DEFAULT//根據cache-control決定是否從網路上取資料。
    LOAD_CACHE_NORMAL//API level 17中已經廢棄, 從API level 11開始作用同LOAD_DEFAULT模式
    LOAD_NO_CACHE//不使用快取,只從網路獲取資料.
    LOAD_CACHE_ELSE_NETWORK//只要本地有,無論是否過期,或者no-cache,都使用快取中的資料。
複製程式碼

一般都是根據網路來判斷快取使用情況

     //載入快取形式
        if (CommonUtils.getNetWorkStatus(context)){//判斷網路是否可用
            // 根據cache-control決定是否從網路上取資料。
            websettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        }else{
            // 只要本地有,無論是否過期,或者no-cache,都使用快取中的資料。
            websettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        }
複製程式碼

頁面返回

  • 我們有時需要實現回退到上一目錄

      @Override
      public boolean onKeyDown(int keyCode, KeyEvent event) {
          if (keyCode == KeyEvent.KEYCODE_BACK) {
              if (webView.canGoBack()) {
                  webView.goBack();//返回上一瀏覽頁面
                  return true;
              } else {
                  finish();//關閉Activity
              }
          }
          return super.onKeyDown(keyCode, event);
      }
    複製程式碼

其他設定

    WebSettings webSettings = webView.getSettings();
    //支援縮放
    webSettings.setSupportZoom(true);  
    //支援內容重新佈局
    webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); 
     //多視窗
    webSettings.supportMultipleWindows(); 
    //當webview呼叫requestFocus時為webview設定節點
    webSettings.setNeedInitialFocus(true); 
    //設定支援縮放
    webSettings.setBuiltInZoomControls(true); 
    //支援通過JS開啟新視窗
    webSettings.setJavaScriptCanOpenWindowsAutomatically(true); 
    //支援自動載入圖片
    webSettings.setLoadsImagesAutomatically(true);  
    //提高渲染的優先順序
     websettings.setRenderPriority(WebSettings.RenderPriority.HIGH);
     // 開啟H5(APPCache)快取功能
     websettings.setAppCacheEnabled(true);
    // 開啟 DOM storage 功能
     websettings.setDomStorageEnabled(true);
    // 應用可以有資料庫
    websettings.setDatabaseEnabled(true);
    // 可以讀取檔案快取(manifest生效)
    websettings.setAllowFileAccess(true);
複製程式碼

相關文章